diff --git a/README.md b/README.md index a5149bf3..4504b72b 100644 --- a/README.md +++ b/README.md @@ -351,10 +351,11 @@ Note: all settings are stored in NVRAM and will be reloaded when device starts. 0x09 reset functions (send this command with confirmed ack only to avoid boot loops!) - 0 = restart device + 0 = restart device (coldstart) 1 = reset MAC counter to zero 2 = reset device to factory settings 3 = flush send queues + 4 = restart device (warmstart) 9 = reboot device to OTA update via Wifi mode 0x0A set LoRaWAN payload send cycle diff --git a/include/globals.h b/include/globals.h index 9e41d441..aaecfceb 100644 --- a/include/globals.h +++ b/include/globals.h @@ -51,10 +51,12 @@ enum sendprio_t { prio_low, prio_normal, prio_high }; enum timesource_t { _gps, _rtc, _lora, _unsynced }; + enum runmode_t { + RUNMODE_POWERCYCLE = 0, RUNMODE_NORMAL, - RUNMODE_UPDATE, - RUNMODE_WAKEUP + RUNMODE_WAKEUP, + RUNMODE_UPDATE }; // Struct holding devices's runtime configuration @@ -125,6 +127,7 @@ extern TaskHandle_t irqHandlerTask, ClockTask; extern TimerHandle_t WifiChanTimer; extern Timezone myTZ; extern time_t userUTCTime; +extern RTC_DATA_ATTR runmode_t RTC_runmode; // application includes #include "led.h" diff --git a/include/lorawan.h b/include/lorawan.h index e459cbf3..e98da2bf 100644 --- a/include/lorawan.h +++ b/include/lorawan.h @@ -22,7 +22,9 @@ #endif extern TaskHandle_t lmicTask, lorasendTask; -extern RTC_DATA_ATTR int RTCseqnoUp, RTCseqnoDn; +extern RTC_NOINIT_ATTR u4_t RTCnetid, RTCdevaddr; +extern RTC_NOINIT_ATTR u1_t RTCnwkKey[16], RTCartKey[16]; +extern RTC_NOINIT_ATTR int RTCseqnoUp, RTCseqnoDn; // table of LORAWAN MAC commands typedef struct { @@ -31,7 +33,7 @@ typedef struct { const uint8_t params; } mac_t; -esp_err_t lora_stack_init(bool joined = false); +esp_err_t lora_stack_init(bool do_join); void lora_setupForNetwork(bool preJoin); void lmictask(void *pvParameters); void gen_lora_deveui(uint8_t *pdeveui); @@ -44,10 +46,10 @@ void showLoraKeys(void); void lora_send(void *pvParameters); void lora_enqueuedata(MessageBuffer_t *message); void lora_queuereset(void); -static void IRAM_ATTR myEventCallback(void *pUserData, ev_t ev); -static void IRAM_ATTR myRxCallback(void *pUserData, uint8_t port, const uint8_t *pMsg, - size_t nMsg); -static void IRAM_ATTR myTxCallback(void *pUserData, int fSuccess); +static void IRAM_ATTR myEventCallback(void *pUserData, ev_t ev); +static void IRAM_ATTR myRxCallback(void *pUserData, uint8_t port, + const uint8_t *pMsg, size_t nMsg); +static void IRAM_ATTR myTxCallback(void *pUserData, int fSuccess); void mac_decode(const uint8_t cmd[], const uint8_t cmdlen, const mac_t table[], const uint8_t tablesize); uint8_t getBattLevel(void); @@ -57,7 +59,7 @@ const char *getCrName(rps_t rps); #if (TIME_SYNC_LORAWAN) static void user_request_network_time_callback(void *pVoidUserUTCTime, - int flagSuccess); + int flagSuccess); #endif #endif \ No newline at end of file diff --git a/include/main.h b/include/main.h index f57ce3f9..9037ccec 100644 --- a/include/main.h +++ b/include/main.h @@ -7,7 +7,7 @@ #include // needed for showing coex sw version #include "globals.h" -#include "power.h" +#include "reset.h" #include "i2c.h" #include "blescan.h" #include "wifiscan.h" @@ -16,7 +16,6 @@ #include "beacon_array.h" #include "ota.h" #include "irqhandler.h" -#include "led.h" #include "spislave.h" #if (HAS_LORA) diff --git a/include/power.h b/include/power.h index 89595727..833597d2 100644 --- a/include/power.h +++ b/include/power.h @@ -3,15 +3,12 @@ #include #include -#include #include #include "i2c.h" #define DEFAULT_VREF 1100 // tbd: use adc2_vref_to_gpio() for better estimate #define NO_OF_SAMPLES 64 // we do some multisampling to get better values -extern RTC_DATA_ATTR runmode_t RTC_runmode; - uint16_t read_voltage(void); void calibrate_voltage(void); bool batt_sufficient(void); @@ -19,13 +16,16 @@ void enter_deepsleep(const int wakeup_sec, const gpio_num_t wakeup_gpio); int64_t exit_deepsleep(void); #ifdef HAS_PMU + #include +enum pmu_power_t { pmu_power_on, pmu_power_off, pmu_power_sleep }; void AXP192_powerevent_IRQ(void); -void AXP192_power(bool on); +void AXP192_power(pmu_power_t powerlevel); void AXP192_init(void); void AXP192_showstatus(void); uint8_t i2c_writeBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len); uint8_t i2c_readBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len); + #endif // HAS_PMU #endif \ No newline at end of file diff --git a/include/rcommand.h b/include/rcommand.h index 78e1bae4..b3205256 100644 --- a/include/rcommand.h +++ b/include/rcommand.h @@ -24,6 +24,6 @@ typedef struct { } cmd_t; void rcommand(const uint8_t cmd[], const uint8_t cmdlength); -void do_reset(); +void do_reset(bool warmstart); #endif diff --git a/include/reset.h b/include/reset.h new file mode 100644 index 00000000..422b69e7 --- /dev/null +++ b/include/reset.h @@ -0,0 +1,13 @@ +#ifndef _RESET_H +#define _RESET_H + +#include +#include +#include "i2c.h" + +void do_reset(bool warmstart); +void do_after_reset(int reason); +void enter_deepsleep(const int wakeup_sec, const gpio_num_t wakeup_gpio); +int64_t exit_deepsleep(void); + +#endif // _RESET_H \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 8cb0728f..7e57dd45 100644 --- a/platformio.ini +++ b/platformio.ini @@ -43,7 +43,7 @@ description = Paxcounter is a device for metering passenger flows in realtime. I [common] ; for release_version use max. 10 chars total, use any decimal format like "a.b.c" -release_version = 1.9.64 +release_version = 1.9.7 ; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running! ; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose debug_level = 4 diff --git a/src/cyclic.cpp b/src/cyclic.cpp index 86eae864..569ed772 100644 --- a/src/cyclic.cpp +++ b/src/cyclic.cpp @@ -20,8 +20,15 @@ void doHousekeeping() { uptime(); // check if update mode trigger switch was set - if (RTC_runmode == RUNMODE_UPDATE) - do_reset(); + if (RTC_runmode == RUNMODE_UPDATE) { + // check battery status if we can before doing ota + if (batt_sufficient()) + do_reset(true); // warmstart to runmode update + else { + ESP_LOGE(TAG, "Battery voltage %dmV too low for OTA", batt_voltage); + RTC_runmode == RUNMODE_NORMAL; // keep running in normal mode + } + } // task storage debugging // ESP_LOGD(TAG, "IRQhandler %d bytes left | Taskstate = %d", @@ -87,7 +94,7 @@ void doHousekeeping() { get_salt(); // get new salt for salting hashes if (ESP.getMinFreeHeap() <= MEM_LOW) // check again - do_reset(); // memory leak, reset device + do_reset(true); // memory leak, reset device } // check free PSRAM memory @@ -98,7 +105,7 @@ void doHousekeeping() { get_salt(); // get new salt for salting hashes if (ESP.getMinFreePsram() <= MEM_LOW) // check again - do_reset(); // memory leak, reset device + do_reset(true); // memory leak, reset device } #endif diff --git a/src/lorawan.cpp b/src/lorawan.cpp index 5f89c787..281a66ad 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -18,9 +18,10 @@ static const char TAG[] = "lora"; #endif #endif -RTC_DATA_ATTR u4_t RTCnetid, RTCdevaddr; -RTC_DATA_ATTR u1_t RTCnwkKey[16], RTCartKey[16]; -RTC_DATA_ATTR int RTCseqnoUp, RTCseqnoDn; +// variable keep its values after restart or wakeup from sleep +RTC_NOINIT_ATTR u4_t RTCnetid, RTCdevaddr; +RTC_NOINIT_ATTR u1_t RTCnwkKey[16], RTCartKey[16]; +RTC_NOINIT_ATTR int RTCseqnoUp, RTCseqnoDn; QueueHandle_t LoraSendQueue; TaskHandle_t lmicTask = NULL, lorasendTask = NULL; @@ -107,10 +108,6 @@ void lora_setupForNetwork(bool preJoin) { getSfName(updr2rps(LMIC.datarate)), getBwName(updr2rps(LMIC.datarate)), getCrName(updr2rps(LMIC.datarate))); - // store keys and counters in RTC memory - LMIC_getSessionKeys(&RTCnetid, &RTCdevaddr, RTCnwkKey, RTCartKey); - RTCseqnoUp = LMIC.seqnoUp; - RTCseqnoDn = LMIC.seqnoDn; } } @@ -295,7 +292,7 @@ void lora_send(void *pvParameters) { } } -esp_err_t lora_stack_init(bool joined) { +esp_err_t lora_stack_init(bool do_join) { assert(SEND_QUEUE_SIZE); LoraSendQueue = xQueueCreate(SEND_QUEUE_SIZE, sizeof(MessageBuffer_t)); if (LoraSendQueue == 0) { @@ -315,8 +312,10 @@ esp_err_t lora_stack_init(bool joined) { &lmicTask, // task handle 1); // CPU core - // start join if we did not wakeup from sleep, else continue session - if (!joined) { + // Start join procedure if not already joined, + // lora_setupForNetwork(true) is called by eventhandler when joined + // else continue current session + if (do_join) { if (!LMIC_startJoining()) ESP_LOGI(TAG, "Already joined"); } else { @@ -324,7 +323,6 @@ esp_err_t lora_stack_init(bool joined) { LMIC_setSession(RTCnetid, RTCdevaddr, RTCnwkKey, RTCartKey); LMIC.seqnoUp = RTCseqnoUp; LMIC.seqnoDn = RTCseqnoDn; - lora_setupForNetwork(true); } // start lmic send task @@ -498,8 +496,8 @@ static void myEventCallback(void *pUserData, ev_t ev) { } // receive message handler -static void myRxCallback(void *pUserData, uint8_t port, - const uint8_t *pMsg, size_t nMsg) { +static void myRxCallback(void *pUserData, uint8_t port, const uint8_t *pMsg, + size_t nMsg) { // display type of received data if (nMsg) diff --git a/src/main.cpp b/src/main.cpp index 86dc8279..2c1c5f04 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -129,14 +129,12 @@ void setup() { esp_log_level_set("*", ESP_LOG_NONE); #endif - ESP_LOGI(TAG, "Starting Software v%s", PROGVERSION); + do_after_reset(rtc_get_reset_reason(0)); - if (RTC_runmode == RUNMODE_WAKEUP) - exit_deepsleep(); - else { - - // print chip information on startup if in verbose mode + // print chip information on startup if in verbose mode after coldstart #if (VERBOSE) + + if (RTC_runmode == RUNMODE_POWERCYCLE) { esp_chip_info_t chip_info; esp_chip_info(&chip_info); ESP_LOGI(TAG, @@ -175,9 +173,8 @@ void setup() { #if (HAS_GPS) ESP_LOGI(TAG, "TinyGPS+ version %s", TinyGPSPlus::libraryVersion()); #endif - -#endif // VERBOSE } +#endif // VERBOSE // open i2c bus i2c_init(); @@ -200,8 +197,8 @@ void setup() { #ifdef HAS_DISPLAY strcat_P(features, " OLED"); DisplayIsOn = cfg.screenon; - init_display(RTC_runmode == RUNMODE_NORMAL ? true - : false); // note: blocking call + // display verbose info only after a coldstart (note: blocking call!) + init_display(RTC_runmode == RUNMODE_POWERCYCLE ? true : false); #endif // scan i2c bus for devices @@ -217,7 +214,7 @@ void setup() { pinMode(BAT_MEASURE_EN, OUTPUT); #endif - // initialize leds +// initialize leds #if (HAS_LED != NOT_A_PIN) pinMode(HAS_LED, OUTPUT); strcat_P(features, " LED"); @@ -270,10 +267,8 @@ void setup() { #if (USE_OTA) strcat_P(features, " OTA"); // reboot to firmware update mode if ota trigger switch is set - if (RTC_runmode == RUNMODE_UPDATE) { - RTC_runmode = RUNMODE_NORMAL; + if (RTC_runmode == RUNMODE_UPDATE) start_ota_update(); - } #endif // start BLE scan callback if BLE function is enabled in NVRAM configuration @@ -317,7 +312,8 @@ void setup() { // initialize LoRa #if (HAS_LORA) strcat_P(features, " LORA"); - assert(lora_stack_init(RTC_runmode == RUNMODE_WAKEUP ? true : false) == + // kick off join, except we come from sleep + assert(lora_stack_init(RTC_runmode == RUNMODE_WAKEUP ? false : true) == ESP_OK); #endif @@ -349,7 +345,7 @@ void setup() { strcat_P(features, " LPPPKD"); #endif - // initialize RTC +// initialize RTC #ifdef HAS_RTC strcat_P(features, " RTC"); assert(rtc_init()); @@ -404,7 +400,7 @@ void setup() { assert(irqHandlerTask != NULL); // has interrupt handler task started? ESP_LOGI(TAG, "Starting Timers..."); - // display interrupt +// display interrupt #ifdef HAS_DISPLAY // https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/ // prescaler 80 -> divides 80 MHz CPU freq to 1 MHz, timer 0, count up @@ -414,7 +410,7 @@ void setup() { timerAlarmEnable(displayIRQ); #endif - // LED Matrix display interrupt +// LED Matrix display interrupt #ifdef HAS_MATRIX_DISPLAY // https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/ // prescaler 80 -> divides 80 MHz CPU freq to 1 MHz, timer 3, count up @@ -424,7 +420,7 @@ void setup() { timerAlarmEnable(matrixDisplayIRQ); #endif - // initialize button +// initialize button #ifdef HAS_BUTTON strcat_P(features, " BTN_"); #ifdef BUTTON_PULLUP diff --git a/src/ota.cpp b/src/ota.cpp index e904cdcf..d78a6453 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -40,12 +40,6 @@ inline String getHeaderValue(String header, String headerName) { void start_ota_update() { - // check battery status if we can before doing ota - if (!batt_sufficient()) { - ESP_LOGE(TAG, "Battery voltage %dmV too low for OTA", batt_voltage); - return; - } - switch_LED(LED_ON); // init display @@ -105,7 +99,7 @@ end: ESP_LOGI(TAG, "Rebooting to %s firmware", (ret == 0) ? "new" : "current"); ota_display(5, "**", ""); // mark line rebooting delay(5000); - ESP.restart(); + do_reset(false); } // start_ota_update diff --git a/src/power.cpp b/src/power.cpp index ce025e7f..65da27b5 100644 --- a/src/power.cpp +++ b/src/power.cpp @@ -5,11 +5,21 @@ // Local logging tag static const char TAG[] = __FILE__; -RTC_DATA_ATTR int64_t sleep_enter_time; -RTC_DATA_ATTR runmode_t RTC_runmode = RUNMODE_NORMAL; +#ifdef BAT_MEASURE_ADC +esp_adc_cal_characteristics_t *adc_characs = + (esp_adc_cal_characteristics_t *)calloc( + 1, sizeof(esp_adc_cal_characteristics_t)); + +#ifndef BAT_MEASURE_ADC_UNIT // ADC1 +static const adc1_channel_t adc_channel = BAT_MEASURE_ADC; +#else // ADC2 +static const adc2_channel_t adc_channel = BAT_MEASURE_ADC; +#endif +static const adc_atten_t atten = ADC_ATTEN_DB_11; +static const adc_unit_t unit = ADC_UNIT_1; +#endif // BAT_MEASURE_ADC #ifdef HAS_PMU - AXP20X_Class pmu; void AXP192_powerevent_IRQ(void) { @@ -37,17 +47,17 @@ void AXP192_powerevent_IRQ(void) { if (pmu.isBattTempHighIRQ()) ESP_LOGI(TAG, "Battery low temperature."); -// esp32 sleep mode, can be exited by pressing user button +// short press -> esp32 deep sleep mode, can be exited by pressing user button #ifdef HAS_BUTTON if (pmu.isPEKShortPressIRQ() && (RTC_runmode == RUNMODE_NORMAL)) { enter_deepsleep(0, HAS_BUTTON); } #endif - // shutdown power + // long press -> shutdown power, can be exited by another longpress if (pmu.isPEKLongtPressIRQ()) { - AXP192_power(false); // switch off Lora, GPS, display - pmu.shutdown(); // switch off device + AXP192_power(pmu_power_off); // switch off Lora, GPS, display + pmu.shutdown(); // switch off device } pmu.clearIRQ(); @@ -56,19 +66,31 @@ void AXP192_powerevent_IRQ(void) { read_voltage(); } -void AXP192_power(bool on) { - if (on) { +void AXP192_power(pmu_power_t powerlevel) { + + switch (powerlevel) { + + case pmu_power_off: + pmu.setChgLEDMode(AXP20X_LED_OFF); + pmu.setPowerOutPut(AXP192_DCDC1, AXP202_OFF); + pmu.setPowerOutPut(AXP192_LDO3, AXP202_OFF); + pmu.setPowerOutPut(AXP192_LDO2, AXP202_OFF); + //pmu.setPowerOutPut(AXP192_DCDC3, AXP202_OFF); + break; + + case pmu_power_sleep: + pmu.setChgLEDMode(AXP20X_LED_BLINK_1HZ); + // we don't cut off DCDC1, because then display blocks i2c bus + pmu.setPowerOutPut(AXP192_LDO3, AXP202_OFF); // gps off + pmu.setPowerOutPut(AXP192_LDO2, AXP202_OFF); // lora off + break; + + default: // all rails power on pmu.setPowerOutPut(AXP192_LDO2, AXP202_ON); // Lora on T-Beam V1.0 pmu.setPowerOutPut(AXP192_LDO3, AXP202_ON); // Gps on T-Beam V1.0 pmu.setPowerOutPut(AXP192_DCDC1, AXP202_ON); // OLED on T-Beam v1.0 pmu.setChgLEDMode(AXP20X_LED_LOW_LEVEL); - // pmu.setChgLEDMode(AXP20X_LED_BLINK_1HZ); - } else { - pmu.setChgLEDMode(AXP20X_LED_OFF); - // we don't cut off power of display, because then display blocks i2c bus - // pmu.setPowerOutPut(AXP192_DCDC1, AXP202_OFF); - pmu.setPowerOutPut(AXP192_LDO3, AXP202_OFF); - pmu.setPowerOutPut(AXP192_LDO2, AXP202_OFF); + break; } } @@ -109,7 +131,7 @@ void AXP192_init(void) { pmu.adc1Enable(AXP202_VBUS_CUR_ADC1, true); // switch power rails on - AXP192_power(true); + AXP192_power(pmu_power_on); #ifdef PMU_INT pinMode(PMU_INT, INPUT_PULLUP); @@ -125,7 +147,7 @@ void AXP192_init(void) { } } -// helper functions for mutexing i2c access +// helper functions for mutexing pmu i2c access uint8_t i2c_readBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len) { if (I2C_MUTEX_LOCK()) { @@ -176,100 +198,6 @@ uint8_t i2c_writeBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len) { #endif // HAS_PMU -#ifdef BAT_MEASURE_ADC -esp_adc_cal_characteristics_t *adc_characs = - (esp_adc_cal_characteristics_t *)calloc( - 1, sizeof(esp_adc_cal_characteristics_t)); - -#ifndef BAT_MEASURE_ADC_UNIT // ADC1 -static const adc1_channel_t adc_channel = BAT_MEASURE_ADC; -#else // ADC2 -static const adc2_channel_t adc_channel = BAT_MEASURE_ADC; -#endif -static const adc_atten_t atten = ADC_ATTEN_DB_11; -static const adc_unit_t unit = ADC_UNIT_1; - -#endif // BAT_MEASURE_ADC - -void enter_deepsleep(const int wakeup_sec, const gpio_num_t wakeup_gpio) { - - if ((!wakeup_sec) && (!wakeup_gpio) && (RTC_runmode == RUNMODE_NORMAL)) - return; - - // set up power domains - esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_ON); - - // set wakeup timer - if (wakeup_sec) - esp_sleep_enable_timer_wakeup(wakeup_sec * 1000000); - - // set wakeup gpio - if (wakeup_gpio != NOT_A_PIN) { - rtc_gpio_isolate(wakeup_gpio); - esp_sleep_enable_ext1_wakeup(1ULL << wakeup_gpio, ESP_EXT1_WAKEUP_ALL_LOW); - } - - // store LMIC counters and time - RTCseqnoUp = LMIC.seqnoUp; - RTCseqnoDn = LMIC.seqnoDn; - - // store sleep enter time - sleep_enter_time = esp_timer_get_time(); - - // halt interrupts accessing i2c bus - mask_user_IRQ(); - -// switch off display -#ifdef HAS_DISPLAY - shutdown_display(); -#endif - -// switch off wifi & ble -#if (BLECOUNTER) - stop_BLEscan(); -#endif - -// switch off power if has PMU -#ifdef HAS_PMU - AXP192_power(false); // switch off Lora, GPS, display -#endif - - // shutdown i2c bus - i2c_deinit(); - - // enter sleep mode - esp_deep_sleep_start(); -} - -int64_t exit_deepsleep(void) { - - int64_t sleep_time_ms = (esp_timer_get_time() - sleep_enter_time) / 1000; - - // switch on power if has PMU -#ifdef HAS_PMU - AXP192_power(true); // power on Lora, GPS, display -#endif - - // re-init i2c bus - void i2c_init(); - - switch (esp_sleep_get_wakeup_cause()) { - case ESP_SLEEP_WAKEUP_EXT1: - case ESP_SLEEP_WAKEUP_TIMER: - RTC_runmode = RUNMODE_WAKEUP; - ESP_LOGI(TAG, "[%0.3f] wake up from deep sleep after %dms", sleep_time_ms); - break; - case ESP_SLEEP_WAKEUP_UNDEFINED: - default: - RTC_runmode = RUNMODE_NORMAL; - } - - if (RTC_runmode == RUNMODE_WAKEUP) - return sleep_time_ms; - else - return -1; -} - void calibrate_voltage(void) { #ifdef BAT_MEASURE_ADC // configure ADC diff --git a/src/rcommand.cpp b/src/rcommand.cpp index 24972c73..293e9fae 100644 --- a/src/rcommand.cpp +++ b/src/rcommand.cpp @@ -5,21 +5,12 @@ // Local logging tag static const char TAG[] = __FILE__; -// helper function -void do_reset() { - ESP_LOGI(TAG, "Remote command: restart device"); -#if (HAS_LORA) - LMIC_shutdown(); -#endif - delay(3000); - esp_restart(); -} - // set of functions that can be triggered by remote commands void set_reset(uint8_t val[]) { switch (val[0]) { - case 0: // restart device - do_reset(); + case 0: // restart device with cold start (clear RTC saved variables) + ESP_LOGI(TAG, "Remote command: restart device cold"); + do_reset(false); break; case 1: // reset MAC counter ESP_LOGI(TAG, "Remote command: reset MAC counter"); @@ -34,6 +25,10 @@ void set_reset(uint8_t val[]) { ESP_LOGI(TAG, "Remote command: flush send queue"); flushQueues(); break; + case 4: // restart device with warm start (keep RTC saved variables) + ESP_LOGI(TAG, "Remote command: restart device warm"); + do_reset(true); + break; case 9: // reset and ask for software update via Wifi OTA ESP_LOGI(TAG, "Remote command: software update via Wifi"); #if (USE_OTA) @@ -346,7 +341,7 @@ static cmd_t table[] = { {0x03, set_gps, 1, true}, {0x04, set_display, 1, true}, {0x05, set_loradr, 1, true}, {0x06, set_lorapower, 1, true}, {0x07, set_loraadr, 1, true}, {0x08, set_screensaver, 1, true}, - {0x09, set_reset, 1, true}, {0x0a, set_sendcycle, 1, true}, + {0x09, set_reset, 1, false}, {0x0a, set_sendcycle, 1, true}, {0x0b, set_wifichancycle, 1, true}, {0x0c, set_blescantime, 1, true}, {0x0d, set_vendorfilter, 1, false}, {0x0e, set_blescan, 1, true}, {0x0f, set_wifiant, 1, true}, {0x10, set_rgblum, 1, true}, diff --git a/src/reset.cpp b/src/reset.cpp new file mode 100644 index 00000000..775fd28a --- /dev/null +++ b/src/reset.cpp @@ -0,0 +1,134 @@ +// Basic Config +#include "globals.h" +#include "reset.h" + +// Local logging tag +static const char TAG[] = __FILE__; + +// variable keep its values after wakeup from sleep +RTC_DATA_ATTR int64_t sleep_enter_time; +// variable keep its values after restart or wakeup from sleep +RTC_NOINIT_ATTR runmode_t RTC_runmode; + +void do_reset(bool warmstart) { + if (warmstart) { + // store LMIC keys and counters in RTC memory +#if (HAS_LORA) + LMIC_getSessionKeys(&RTCnetid, &RTCdevaddr, RTCnwkKey, RTCartKey); + RTCseqnoUp = LMIC.seqnoUp; + RTCseqnoDn = LMIC.seqnoDn; +#endif + ESP_LOGI(TAG, "restarting device (warmstart), keeping runmode %d", + RTC_runmode); + } else { +#if (HAS_LORA) + if (RTC_runmode == RUNMODE_NORMAL) + LMIC_shutdown(); +#endif + RTC_runmode = RUNMODE_POWERCYCLE; + ESP_LOGI(TAG, "restarting device (coldstart), set runmode %d", RTC_runmode); + } + esp_restart(); +} + +void do_after_reset(int reason) { + + switch (reason) { + + case POWERON_RESET: // 0x01 Vbat power on reset + case RTCWDT_BROWN_OUT_RESET: // 0x0f Reset when the vdd voltage is not + // stable + RTC_runmode = RUNMODE_POWERCYCLE; + break; + + case DEEPSLEEP_RESET: // 0x05 Deep Sleep reset digital core + RTC_runmode = RUNMODE_WAKEUP; + exit_deepsleep(); + break; + + case SW_RESET: // 0x03 Software reset digital core + case OWDT_RESET: // 0x04 Legacy watch dog reset digital core + case SDIO_RESET: // 0x06 Reset by SLC module, reset digital core + case TG0WDT_SYS_RESET: // 0x07 Timer Group0 Watch dog reset digital core + case TG1WDT_SYS_RESET: // 0x08 Timer Group1 Watch dog reset digital core + case RTCWDT_SYS_RESET: // 0x09 RTC Watch dog Reset digital core + case INTRUSION_RESET: // 0x0a Instrusion tested to reset CPU + case TGWDT_CPU_RESET: // 0x0b Time Group reset CPU + case SW_CPU_RESET: // 0x0c Software reset CPU + case RTCWDT_CPU_RESET: // 0x0d RTC Watch dog Reset CPU + case EXT_CPU_RESET: // 0x0e for APP CPU, reseted by PRO CPU + case RTCWDT_RTC_RESET: // 0x10 RTC Watch dog reset digital core and rtc mode + default: + break; + } + + ESP_LOGI(TAG, "Starting Software v%s, runmode %d", PROGVERSION, RTC_runmode); +} + +void enter_deepsleep(const int wakeup_sec, const gpio_num_t wakeup_gpio) { + + if ((!wakeup_sec) && (!wakeup_gpio) && (RTC_runmode == RUNMODE_NORMAL)) + return; + + // set up power domains + esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_ON); + + // set wakeup timer + if (wakeup_sec) + esp_sleep_enable_timer_wakeup(wakeup_sec * 1000000); + + // set wakeup gpio + if (wakeup_gpio != NOT_A_PIN) { + rtc_gpio_isolate(wakeup_gpio); + esp_sleep_enable_ext1_wakeup(1ULL << wakeup_gpio, ESP_EXT1_WAKEUP_ALL_LOW); + } + + // store sleep enter time + sleep_enter_time = esp_timer_get_time(); + +// store LMIC keys and counters in RTC memory +#if (HAS_LORA) + LMIC_getSessionKeys(&RTCnetid, &RTCdevaddr, RTCnwkKey, RTCartKey); + RTCseqnoUp = LMIC.seqnoUp; + RTCseqnoDn = LMIC.seqnoDn; +#endif + + // halt interrupts accessing i2c bus + mask_user_IRQ(); + +// switch off display +#ifdef HAS_DISPLAY + shutdown_display(); +#endif + +// switch off wifi & ble +#if (BLECOUNTER) + stop_BLEscan(); +#endif + +// reduce power if has PMU +#ifdef HAS_PMU + AXP192_power(pmu_power_sleep); +#endif + + // shutdown i2c bus + i2c_deinit(); + + // enter sleep mode + esp_deep_sleep_start(); +} + +int64_t exit_deepsleep(void) { + + int64_t sleep_time_ms = (esp_timer_get_time() - sleep_enter_time) / 1000; + + // re-init i2c bus + void i2c_init(); + + // switch on power if has PMU +#ifdef HAS_PMU + AXP192_power(pmu_power_on); // power on Lora, GPS, display +#endif + + return sleep_time_ms; +} \ No newline at end of file