Skip to content

Commit

Permalink
Changed const variables to static const
Browse files Browse the repository at this point in the history
Introduced a fast_exit mode to the daemon to support a faster restart

Added a call to Wire.end() to the initialization of the I2C bus. This allows  to re-init the bus at any time with the same call.

After half of the timeout the ATTiny starts to re-initialize the I2C bus every second as long as there is no new communication with the RPi.

The combination of measures should allow for a faster recovery if the I2C bus is blocked
  • Loading branch information
jbaumann committed Jan 24, 2021
1 parent 3707c0d commit 4108a2e
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 38 deletions.
23 changes: 14 additions & 9 deletions daemon/attiny_daemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@
from collections.abc import Mapping
from pathlib import Path
from attiny_i2c import ATTiny
#from attiny_i2c_new import ATTiny

### Global configuration of the daemon. You should know what you do if you change
### these values.

# Version information
major = 2
minor = 12
patch = 3
minor = 13
patch = 1

# config file is in the same directory as the script:
_configfile_default = str(Path(__file__).parent.absolute()) + "/attiny_daemon.cfg"
Expand Down Expand Up @@ -82,6 +83,7 @@ def main(*args):
logging.info("Merging completed")

# loop until stopped or error
fast_exit = False
set_unprimed = False
try:
while True:
Expand All @@ -91,6 +93,7 @@ def main(*args):
logging.error("Lost connection to ATTiny.")
# disable to fasten restart
# set_unprimed = True # we still try to reset primed
fast_exit = True
exit(1) # executes finally clause and lets the system restart the daemon

if should_shutdown > SL_INITIATED:
Expand Down Expand Up @@ -120,13 +123,15 @@ def main(*args):
except Exception as e:
logging.error("An exception occurred: '" + str(e) + "' Exiting...")
finally:
# will not be executed on SIGTERM, leaving primed set to the config value
primed = config[Config.PRIMED]
if args.nodaemon or set_unprimed:
primed = False
if primed == False:
logging.info("Trying to reset primed flag")
attiny.set_primed(primed)
if fast_exit == False:
# will not be executed on SIGTERM, leaving primed set to the config value
primed = config[Config.PRIMED]
if args.nodaemon or set_unprimed:
primed = False
if primed == False:
logging.info("Trying to reset primed flag")
attiny.set_primed(primed)
del attiny


def parse_cmdline(args: Tuple[Any]) -> Namespace:
Expand Down
34 changes: 17 additions & 17 deletions firmware/ATTinyDaemon/ATTinyDaemon.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
/*
Our version number - used by the daemon to ensure that the major number is equal between firmware and daemon
*/
const uint32_t MAJOR = 2;
const uint32_t MINOR = 13;
const uint32_t PATCH = 7;
static const uint32_t MAJOR = 2;
static const uint32_t MINOR = 13;
static const uint32_t PATCH = 14;

/*
Flash size definition
Expand Down Expand Up @@ -54,11 +54,11 @@ const uint32_t PATCH = 7;
7 SCK ADC1 PCINT2 PB2 INT0
8 VCC
*/
const uint8_t LED_BUTTON = PB4; // combined led/button pin
const uint8_t PIN_SWITCH = PB1; // pin used for pushing the switch (the normal way to reset the RPi)
const uint8_t PIN_RESET = PB5; // Reset pin (used as an alternative direct way to reset the RPi)
static const uint8_t LED_BUTTON = PB4; // combined led/button pin
static const uint8_t PIN_SWITCH = PB1; // pin used for pushing the switch (the normal way to reset the RPi)
static const uint8_t PIN_RESET = PB5; // Reset pin (used as an alternative direct way to reset the RPi)
// The following pin definition is needed as a define statement to allow the macro expansion in handleVoltages.ino
#define EXT_VOLTAGE ADC3 // ADC number, used to measure external or RPi voltage (Ax, ADCx or x)
#define EXT_VOLTAGE ADC3 // ADC number, used to measure external or RPi voltage (Ax, ADCx or x)


#if defined SERIAL_DEBUG
Expand All @@ -69,10 +69,10 @@ const uint8_t PIN_RESET = PB5; // Reset pin (used as an alternative
/*
Basic constants
*/
const uint8_t BLINK_TIME = 100; // time in milliseconds for the LED to blink
const uint16_t MIN_POWER_LEVEL = 4700; // the voltage level seen as "ON" at the external voltage after a reset
const uint8_t NUM_MEASUREMENTS = 5; // the number of ADC measurements we average, should be larger than 4
const uint8_t SW_TO_PULSE_DIV = 4; // The divisor from switch_delay_revocery to delay between multiple pulses
static const uint8_t BLINK_TIME = 100; // time in milliseconds for the LED to blink
static const uint16_t MIN_POWER_LEVEL = 4700; // the voltage level seen as "ON" at the external voltage after a reset
static const uint8_t NUM_MEASUREMENTS = 5; // the number of ADC measurements we average, should be larger than 4
static const uint8_t SW_TO_PULSE_DIV = 4; // The divisor from switch_delay_revocery to delay between multiple pulses

/*
Values modelling the different states the system can be in
Expand Down Expand Up @@ -125,16 +125,16 @@ enum EEPROM_Address {
This way, whenever the minor or major version changes, the eeprom will be initialized again to
ensure that everything works without problems.
*/
const uint8_t BITS_FOR_MINOR = 5;
const uint8_t BITS_FOR_MAJOR = CHAR_BIT - BITS_FOR_MINOR;
const uint8_t MINOR_PART = MINOR & ((1<<BITS_FOR_MINOR)-1);
const uint8_t MAJOR_PART = (MAJOR & BITS_FOR_MAJOR) << BITS_FOR_MINOR;
const uint8_t EEPROM_INIT_VALUE = MAJOR_PART | MINOR_PART;
static const uint8_t BITS_FOR_MINOR = 5;
static const uint8_t BITS_FOR_MAJOR = CHAR_BIT - BITS_FOR_MINOR;
static const uint8_t MINOR_PART = MINOR & ((1<<BITS_FOR_MINOR)-1);
static const uint8_t MAJOR_PART = (MAJOR & BITS_FOR_MAJOR) << BITS_FOR_MINOR;
static const uint8_t EEPROM_INIT_VALUE = MAJOR_PART | MINOR_PART;

/*
I2C interface and register definitions
*/
const uint8_t I2C_ADDRESS = 0x37;
static const uint8_t I2C_ADDRESS = 0x37;

enum class Register : uint8_t {
last_access = 0x01,
Expand Down
4 changes: 2 additions & 2 deletions firmware/ATTinyDaemon/ATTinyDaemon.ino
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
/*
Store major and minor version and the patch level in a constant
*/
const uint32_t prog_version = (MAJOR << 16) | (MINOR << 8) | PATCH;
static const uint32_t prog_version = (MAJOR << 16) | (MINOR << 8) | PATCH;

/*
The state variable encapsulates the all-over state of the system (ATTiny and RPi
Expand Down Expand Up @@ -93,7 +93,7 @@ volatile bool update_eeprom = false;
have been changed
*/
volatile uint8_t reset_bat_voltage = false;

void setup() {
mcusr_mirror = MCUSR;
reset_watchdog (); // do this first in case WDT fires
Expand Down
3 changes: 1 addition & 2 deletions firmware/ATTinyDaemon/handleI2C.ino
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ void init_I2C() {
#if defined SERIAL_DEBUG
Serial.println(F("In init_I2C()"));
#endif

Wire.end();
Wire.begin(I2C_ADDRESS);
Wire.onRequest(request_event);
Wire.onReceive(receive_event);
// Wire.onInterrupt(disable_watchdog);
}

/*
Expand Down
22 changes: 14 additions & 8 deletions firmware/ATTinyDaemon/handleState.ino
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ void handle_state() {
// already signalled that it is doing so
if (state <= State::warn_state) {
// we first check whether the Raspberry is already in the shutdown process
if(!(should_shutdown & Shutdown_Cause::rpi_initiated)) {
if (!(should_shutdown & Shutdown_Cause::rpi_initiated)) {
if (should_shutdown > Shutdown_Cause::rpi_initiated && (seconds_safe < timeout)) {
// RPi should take action, possibly shut down. Signal by blinking 5 times
blink_led(5, BLINK_TIME);
Expand Down Expand Up @@ -77,7 +77,7 @@ void handle_state() {

/*
Act on the current state
*/
*/
void act_on_state_change() {
// This is placed before the general check of all stages as to
// not duplicate the code of the shutdown_state
Expand Down Expand Up @@ -108,7 +108,7 @@ void act_on_state_change() {
should_shutdown = Shutdown_Cause::none;
} else if (state == State::warn_to_running) {
// we have recovered from a warn state and are now at a safe voltage
// we switch to State::running_state and let that state (below) handle
// we switch to State::running_state and let that state (below) handle
// the restart
state = State::running_state;
should_shutdown = Shutdown_Cause::none;
Expand All @@ -119,15 +119,21 @@ void act_on_state_change() {

if (state == State::running_state) {
bool should_restart = false;
bool reset_i2c_bus = false;

if(vext_off_is_shutdown) {
if (vext_off_is_shutdown) {
should_restart = ext_voltage < MIN_POWER_LEVEL;
} else {
ATOMIC_BLOCK(ATOMIC_FORCEON) {
should_restart = seconds > timeout;
reset_i2c_bus = seconds > (timeout / 2);
}
}

// reset bus until we get connection again or until time is out
if (reset_i2c_bus) {
init_I2C();
}
if (should_restart) {
if (primed == 1) {
// RPi has not accessed the I2C interface for more than timeout seconds.
Expand Down Expand Up @@ -157,11 +163,11 @@ void voltage_dependent_state_change() {
}

if (bat_voltage <= ups_shutdown_voltage_safe) {
if(state < State::warn_to_shutdown) {
if (state < State::warn_to_shutdown) {
state = State::warn_to_shutdown;
}
} else if (bat_voltage <= warn_voltage_safe) {
if(state < State::warn_state) {
if (state < State::warn_state) {
state = State::warn_state;
should_shutdown |= Shutdown_Cause::bat_voltage;
}
Expand Down Expand Up @@ -198,10 +204,10 @@ void voltage_dependent_state_change() {
/*
When we get an I2C communication then this might change our state (because now we
know the RPi is alive). Called only during an interrupt.
*/
*/
void i2c_triggered_state_change() {
// If we are in an unclear state, then a communication from the RPi moves us to running state
if (state == State::unclear_state) {
state = State::running_state;
}
}
}

0 comments on commit 4108a2e

Please sign in to comment.