added new reset logic; deep sleep fixes

This commit is contained in:
Verkehrsrot 2019-10-20 20:05:13 +02:00
parent f3b3838e09
commit bc034b1a67
15 changed files with 256 additions and 186 deletions

View File

@ -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!) 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 1 = reset MAC counter to zero
2 = reset device to factory settings 2 = reset device to factory settings
3 = flush send queues 3 = flush send queues
4 = restart device (warmstart)
9 = reboot device to OTA update via Wifi mode 9 = reboot device to OTA update via Wifi mode
0x0A set LoRaWAN payload send cycle 0x0A set LoRaWAN payload send cycle

View File

@ -51,10 +51,12 @@
enum sendprio_t { prio_low, prio_normal, prio_high }; enum sendprio_t { prio_low, prio_normal, prio_high };
enum timesource_t { _gps, _rtc, _lora, _unsynced }; enum timesource_t { _gps, _rtc, _lora, _unsynced };
enum runmode_t { enum runmode_t {
RUNMODE_POWERCYCLE = 0,
RUNMODE_NORMAL, RUNMODE_NORMAL,
RUNMODE_UPDATE, RUNMODE_WAKEUP,
RUNMODE_WAKEUP RUNMODE_UPDATE
}; };
// Struct holding devices's runtime configuration // Struct holding devices's runtime configuration
@ -125,6 +127,7 @@ extern TaskHandle_t irqHandlerTask, ClockTask;
extern TimerHandle_t WifiChanTimer; extern TimerHandle_t WifiChanTimer;
extern Timezone myTZ; extern Timezone myTZ;
extern time_t userUTCTime; extern time_t userUTCTime;
extern RTC_DATA_ATTR runmode_t RTC_runmode;
// application includes // application includes
#include "led.h" #include "led.h"

View File

@ -22,7 +22,9 @@
#endif #endif
extern TaskHandle_t lmicTask, lorasendTask; 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 // table of LORAWAN MAC commands
typedef struct { typedef struct {
@ -31,7 +33,7 @@ typedef struct {
const uint8_t params; const uint8_t params;
} mac_t; } 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 lora_setupForNetwork(bool preJoin);
void lmictask(void *pvParameters); void lmictask(void *pvParameters);
void gen_lora_deveui(uint8_t *pdeveui); void gen_lora_deveui(uint8_t *pdeveui);
@ -45,8 +47,8 @@ void lora_send(void *pvParameters);
void lora_enqueuedata(MessageBuffer_t *message); void lora_enqueuedata(MessageBuffer_t *message);
void lora_queuereset(void); void lora_queuereset(void);
static void IRAM_ATTR myEventCallback(void *pUserData, ev_t ev); static void IRAM_ATTR myEventCallback(void *pUserData, ev_t ev);
static void IRAM_ATTR myRxCallback(void *pUserData, uint8_t port, const uint8_t *pMsg, static void IRAM_ATTR myRxCallback(void *pUserData, uint8_t port,
size_t nMsg); const uint8_t *pMsg, size_t nMsg);
static void IRAM_ATTR myTxCallback(void *pUserData, int fSuccess); static void IRAM_ATTR myTxCallback(void *pUserData, int fSuccess);
void mac_decode(const uint8_t cmd[], const uint8_t cmdlen, const mac_t table[], void mac_decode(const uint8_t cmd[], const uint8_t cmdlen, const mac_t table[],
const uint8_t tablesize); const uint8_t tablesize);

View File

@ -7,7 +7,7 @@
#include <esp_coexist.h> // needed for showing coex sw version #include <esp_coexist.h> // needed for showing coex sw version
#include "globals.h" #include "globals.h"
#include "power.h" #include "reset.h"
#include "i2c.h" #include "i2c.h"
#include "blescan.h" #include "blescan.h"
#include "wifiscan.h" #include "wifiscan.h"
@ -16,7 +16,6 @@
#include "beacon_array.h" #include "beacon_array.h"
#include "ota.h" #include "ota.h"
#include "irqhandler.h" #include "irqhandler.h"
#include "led.h"
#include "spislave.h" #include "spislave.h"
#if (HAS_LORA) #if (HAS_LORA)

View File

@ -3,15 +3,12 @@
#include <Arduino.h> #include <Arduino.h>
#include <driver/adc.h> #include <driver/adc.h>
#include <driver/rtc_io.h>
#include <esp_adc_cal.h> #include <esp_adc_cal.h>
#include "i2c.h" #include "i2c.h"
#define DEFAULT_VREF 1100 // tbd: use adc2_vref_to_gpio() for better estimate #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 #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); uint16_t read_voltage(void);
void calibrate_voltage(void); void calibrate_voltage(void);
bool batt_sufficient(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); int64_t exit_deepsleep(void);
#ifdef HAS_PMU #ifdef HAS_PMU
#include <axp20x.h> #include <axp20x.h>
enum pmu_power_t { pmu_power_on, pmu_power_off, pmu_power_sleep };
void AXP192_powerevent_IRQ(void); void AXP192_powerevent_IRQ(void);
void AXP192_power(bool on); void AXP192_power(pmu_power_t powerlevel);
void AXP192_init(void); void AXP192_init(void);
void AXP192_showstatus(void); void AXP192_showstatus(void);
uint8_t i2c_writeBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len); 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); uint8_t i2c_readBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len);
#endif // HAS_PMU #endif // HAS_PMU
#endif #endif

View File

@ -24,6 +24,6 @@ typedef struct {
} cmd_t; } cmd_t;
void rcommand(const uint8_t cmd[], const uint8_t cmdlength); void rcommand(const uint8_t cmd[], const uint8_t cmdlength);
void do_reset(); void do_reset(bool warmstart);
#endif #endif

13
include/reset.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef _RESET_H
#define _RESET_H
#include <driver/rtc_io.h>
#include <rom/rtc.h>
#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

View File

@ -43,7 +43,7 @@ description = Paxcounter is a device for metering passenger flows in realtime. I
[common] [common]
; for release_version use max. 10 chars total, use any decimal format like "a.b.c" ; 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! ; 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 ; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose
debug_level = 4 debug_level = 4

View File

@ -20,8 +20,15 @@ void doHousekeeping() {
uptime(); uptime();
// check if update mode trigger switch was set // check if update mode trigger switch was set
if (RTC_runmode == RUNMODE_UPDATE) if (RTC_runmode == RUNMODE_UPDATE) {
do_reset(); // 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 // // task storage debugging //
ESP_LOGD(TAG, "IRQhandler %d bytes left | Taskstate = %d", ESP_LOGD(TAG, "IRQhandler %d bytes left | Taskstate = %d",
@ -87,7 +94,7 @@ void doHousekeeping() {
get_salt(); // get new salt for salting hashes get_salt(); // get new salt for salting hashes
if (ESP.getMinFreeHeap() <= MEM_LOW) // check again if (ESP.getMinFreeHeap() <= MEM_LOW) // check again
do_reset(); // memory leak, reset device do_reset(true); // memory leak, reset device
} }
// check free PSRAM memory // check free PSRAM memory
@ -98,7 +105,7 @@ void doHousekeeping() {
get_salt(); // get new salt for salting hashes get_salt(); // get new salt for salting hashes
if (ESP.getMinFreePsram() <= MEM_LOW) // check again if (ESP.getMinFreePsram() <= MEM_LOW) // check again
do_reset(); // memory leak, reset device do_reset(true); // memory leak, reset device
} }
#endif #endif

View File

@ -18,9 +18,10 @@ static const char TAG[] = "lora";
#endif #endif
#endif #endif
RTC_DATA_ATTR u4_t RTCnetid, RTCdevaddr; // variable keep its values after restart or wakeup from sleep
RTC_DATA_ATTR u1_t RTCnwkKey[16], RTCartKey[16]; RTC_NOINIT_ATTR u4_t RTCnetid, RTCdevaddr;
RTC_DATA_ATTR int RTCseqnoUp, RTCseqnoDn; RTC_NOINIT_ATTR u1_t RTCnwkKey[16], RTCartKey[16];
RTC_NOINIT_ATTR int RTCseqnoUp, RTCseqnoDn;
QueueHandle_t LoraSendQueue; QueueHandle_t LoraSendQueue;
TaskHandle_t lmicTask = NULL, lorasendTask = NULL; TaskHandle_t lmicTask = NULL, lorasendTask = NULL;
@ -107,10 +108,6 @@ void lora_setupForNetwork(bool preJoin) {
getSfName(updr2rps(LMIC.datarate)), getSfName(updr2rps(LMIC.datarate)),
getBwName(updr2rps(LMIC.datarate)), getBwName(updr2rps(LMIC.datarate)),
getCrName(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); assert(SEND_QUEUE_SIZE);
LoraSendQueue = xQueueCreate(SEND_QUEUE_SIZE, sizeof(MessageBuffer_t)); LoraSendQueue = xQueueCreate(SEND_QUEUE_SIZE, sizeof(MessageBuffer_t));
if (LoraSendQueue == 0) { if (LoraSendQueue == 0) {
@ -315,8 +312,10 @@ esp_err_t lora_stack_init(bool joined) {
&lmicTask, // task handle &lmicTask, // task handle
1); // CPU core 1); // CPU core
// start join if we did not wakeup from sleep, else continue session // Start join procedure if not already joined,
if (!joined) { // lora_setupForNetwork(true) is called by eventhandler when joined
// else continue current session
if (do_join) {
if (!LMIC_startJoining()) if (!LMIC_startJoining())
ESP_LOGI(TAG, "Already joined"); ESP_LOGI(TAG, "Already joined");
} else { } else {
@ -324,7 +323,6 @@ esp_err_t lora_stack_init(bool joined) {
LMIC_setSession(RTCnetid, RTCdevaddr, RTCnwkKey, RTCartKey); LMIC_setSession(RTCnetid, RTCdevaddr, RTCnwkKey, RTCartKey);
LMIC.seqnoUp = RTCseqnoUp; LMIC.seqnoUp = RTCseqnoUp;
LMIC.seqnoDn = RTCseqnoDn; LMIC.seqnoDn = RTCseqnoDn;
lora_setupForNetwork(true);
} }
// start lmic send task // start lmic send task
@ -498,8 +496,8 @@ static void myEventCallback(void *pUserData, ev_t ev) {
} }
// receive message handler // receive message handler
static void myRxCallback(void *pUserData, uint8_t port, static void myRxCallback(void *pUserData, uint8_t port, const uint8_t *pMsg,
const uint8_t *pMsg, size_t nMsg) { size_t nMsg) {
// display type of received data // display type of received data
if (nMsg) if (nMsg)

View File

@ -129,14 +129,12 @@ void setup() {
esp_log_level_set("*", ESP_LOG_NONE); esp_log_level_set("*", ESP_LOG_NONE);
#endif #endif
ESP_LOGI(TAG, "Starting Software v%s", PROGVERSION); do_after_reset(rtc_get_reset_reason(0));
if (RTC_runmode == RUNMODE_WAKEUP) // print chip information on startup if in verbose mode after coldstart
exit_deepsleep();
else {
// print chip information on startup if in verbose mode
#if (VERBOSE) #if (VERBOSE)
if (RTC_runmode == RUNMODE_POWERCYCLE) {
esp_chip_info_t chip_info; esp_chip_info_t chip_info;
esp_chip_info(&chip_info); esp_chip_info(&chip_info);
ESP_LOGI(TAG, ESP_LOGI(TAG,
@ -175,9 +173,8 @@ void setup() {
#if (HAS_GPS) #if (HAS_GPS)
ESP_LOGI(TAG, "TinyGPS+ version %s", TinyGPSPlus::libraryVersion()); ESP_LOGI(TAG, "TinyGPS+ version %s", TinyGPSPlus::libraryVersion());
#endif #endif
#endif // VERBOSE
} }
#endif // VERBOSE
// open i2c bus // open i2c bus
i2c_init(); i2c_init();
@ -200,8 +197,8 @@ void setup() {
#ifdef HAS_DISPLAY #ifdef HAS_DISPLAY
strcat_P(features, " OLED"); strcat_P(features, " OLED");
DisplayIsOn = cfg.screenon; DisplayIsOn = cfg.screenon;
init_display(RTC_runmode == RUNMODE_NORMAL ? true // display verbose info only after a coldstart (note: blocking call!)
: false); // note: blocking call init_display(RTC_runmode == RUNMODE_POWERCYCLE ? true : false);
#endif #endif
// scan i2c bus for devices // scan i2c bus for devices
@ -217,7 +214,7 @@ void setup() {
pinMode(BAT_MEASURE_EN, OUTPUT); pinMode(BAT_MEASURE_EN, OUTPUT);
#endif #endif
// initialize leds // initialize leds
#if (HAS_LED != NOT_A_PIN) #if (HAS_LED != NOT_A_PIN)
pinMode(HAS_LED, OUTPUT); pinMode(HAS_LED, OUTPUT);
strcat_P(features, " LED"); strcat_P(features, " LED");
@ -270,10 +267,8 @@ void setup() {
#if (USE_OTA) #if (USE_OTA)
strcat_P(features, " OTA"); strcat_P(features, " OTA");
// reboot to firmware update mode if ota trigger switch is set // reboot to firmware update mode if ota trigger switch is set
if (RTC_runmode == RUNMODE_UPDATE) { if (RTC_runmode == RUNMODE_UPDATE)
RTC_runmode = RUNMODE_NORMAL;
start_ota_update(); start_ota_update();
}
#endif #endif
// start BLE scan callback if BLE function is enabled in NVRAM configuration // start BLE scan callback if BLE function is enabled in NVRAM configuration
@ -317,7 +312,8 @@ void setup() {
// initialize LoRa // initialize LoRa
#if (HAS_LORA) #if (HAS_LORA)
strcat_P(features, " 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); ESP_OK);
#endif #endif
@ -349,7 +345,7 @@ void setup() {
strcat_P(features, " LPPPKD"); strcat_P(features, " LPPPKD");
#endif #endif
// initialize RTC // initialize RTC
#ifdef HAS_RTC #ifdef HAS_RTC
strcat_P(features, " RTC"); strcat_P(features, " RTC");
assert(rtc_init()); assert(rtc_init());
@ -404,7 +400,7 @@ void setup() {
assert(irqHandlerTask != NULL); // has interrupt handler task started? assert(irqHandlerTask != NULL); // has interrupt handler task started?
ESP_LOGI(TAG, "Starting Timers..."); ESP_LOGI(TAG, "Starting Timers...");
// display interrupt // display interrupt
#ifdef HAS_DISPLAY #ifdef HAS_DISPLAY
// https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/ // https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/
// prescaler 80 -> divides 80 MHz CPU freq to 1 MHz, timer 0, count up // prescaler 80 -> divides 80 MHz CPU freq to 1 MHz, timer 0, count up
@ -414,7 +410,7 @@ void setup() {
timerAlarmEnable(displayIRQ); timerAlarmEnable(displayIRQ);
#endif #endif
// LED Matrix display interrupt // LED Matrix display interrupt
#ifdef HAS_MATRIX_DISPLAY #ifdef HAS_MATRIX_DISPLAY
// https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/ // https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/
// prescaler 80 -> divides 80 MHz CPU freq to 1 MHz, timer 3, count up // prescaler 80 -> divides 80 MHz CPU freq to 1 MHz, timer 3, count up
@ -424,7 +420,7 @@ void setup() {
timerAlarmEnable(matrixDisplayIRQ); timerAlarmEnable(matrixDisplayIRQ);
#endif #endif
// initialize button // initialize button
#ifdef HAS_BUTTON #ifdef HAS_BUTTON
strcat_P(features, " BTN_"); strcat_P(features, " BTN_");
#ifdef BUTTON_PULLUP #ifdef BUTTON_PULLUP

View File

@ -40,12 +40,6 @@ inline String getHeaderValue(String header, String headerName) {
void start_ota_update() { 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); switch_LED(LED_ON);
// init display // init display
@ -105,7 +99,7 @@ end:
ESP_LOGI(TAG, "Rebooting to %s firmware", (ret == 0) ? "new" : "current"); ESP_LOGI(TAG, "Rebooting to %s firmware", (ret == 0) ? "new" : "current");
ota_display(5, "**", ""); // mark line rebooting ota_display(5, "**", ""); // mark line rebooting
delay(5000); delay(5000);
ESP.restart(); do_reset(false);
} // start_ota_update } // start_ota_update

View File

@ -5,11 +5,21 @@
// Local logging tag // Local logging tag
static const char TAG[] = __FILE__; static const char TAG[] = __FILE__;
RTC_DATA_ATTR int64_t sleep_enter_time; #ifdef BAT_MEASURE_ADC
RTC_DATA_ATTR runmode_t RTC_runmode = RUNMODE_NORMAL; 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 #ifdef HAS_PMU
AXP20X_Class pmu; AXP20X_Class pmu;
void AXP192_powerevent_IRQ(void) { void AXP192_powerevent_IRQ(void) {
@ -37,16 +47,16 @@ void AXP192_powerevent_IRQ(void) {
if (pmu.isBattTempHighIRQ()) if (pmu.isBattTempHighIRQ())
ESP_LOGI(TAG, "Battery low temperature."); 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 #ifdef HAS_BUTTON
if (pmu.isPEKShortPressIRQ() && (RTC_runmode == RUNMODE_NORMAL)) { if (pmu.isPEKShortPressIRQ() && (RTC_runmode == RUNMODE_NORMAL)) {
enter_deepsleep(0, HAS_BUTTON); enter_deepsleep(0, HAS_BUTTON);
} }
#endif #endif
// shutdown power // long press -> shutdown power, can be exited by another longpress
if (pmu.isPEKLongtPressIRQ()) { if (pmu.isPEKLongtPressIRQ()) {
AXP192_power(false); // switch off Lora, GPS, display AXP192_power(pmu_power_off); // switch off Lora, GPS, display
pmu.shutdown(); // switch off device pmu.shutdown(); // switch off device
} }
@ -56,19 +66,31 @@ void AXP192_powerevent_IRQ(void) {
read_voltage(); read_voltage();
} }
void AXP192_power(bool on) { void AXP192_power(pmu_power_t powerlevel) {
if (on) {
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_LDO2, AXP202_ON); // Lora on T-Beam V1.0
pmu.setPowerOutPut(AXP192_LDO3, AXP202_ON); // Gps 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.setPowerOutPut(AXP192_DCDC1, AXP202_ON); // OLED on T-Beam v1.0
pmu.setChgLEDMode(AXP20X_LED_LOW_LEVEL); pmu.setChgLEDMode(AXP20X_LED_LOW_LEVEL);
// pmu.setChgLEDMode(AXP20X_LED_BLINK_1HZ); break;
} 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);
} }
} }
@ -109,7 +131,7 @@ void AXP192_init(void) {
pmu.adc1Enable(AXP202_VBUS_CUR_ADC1, true); pmu.adc1Enable(AXP202_VBUS_CUR_ADC1, true);
// switch power rails on // switch power rails on
AXP192_power(true); AXP192_power(pmu_power_on);
#ifdef PMU_INT #ifdef PMU_INT
pinMode(PMU_INT, INPUT_PULLUP); 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) { uint8_t i2c_readBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len) {
if (I2C_MUTEX_LOCK()) { 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 #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) { void calibrate_voltage(void) {
#ifdef BAT_MEASURE_ADC #ifdef BAT_MEASURE_ADC
// configure ADC // configure ADC

View File

@ -5,21 +5,12 @@
// Local logging tag // Local logging tag
static const char TAG[] = __FILE__; 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 // set of functions that can be triggered by remote commands
void set_reset(uint8_t val[]) { void set_reset(uint8_t val[]) {
switch (val[0]) { switch (val[0]) {
case 0: // restart device case 0: // restart device with cold start (clear RTC saved variables)
do_reset(); ESP_LOGI(TAG, "Remote command: restart device cold");
do_reset(false);
break; break;
case 1: // reset MAC counter case 1: // reset MAC counter
ESP_LOGI(TAG, "Remote command: 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"); ESP_LOGI(TAG, "Remote command: flush send queue");
flushQueues(); flushQueues();
break; 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 case 9: // reset and ask for software update via Wifi OTA
ESP_LOGI(TAG, "Remote command: software update via Wifi"); ESP_LOGI(TAG, "Remote command: software update via Wifi");
#if (USE_OTA) #if (USE_OTA)
@ -346,7 +341,7 @@ static cmd_t table[] = {
{0x03, set_gps, 1, true}, {0x04, set_display, 1, true}, {0x03, set_gps, 1, true}, {0x04, set_display, 1, true},
{0x05, set_loradr, 1, true}, {0x06, set_lorapower, 1, true}, {0x05, set_loradr, 1, true}, {0x06, set_lorapower, 1, true},
{0x07, set_loraadr, 1, true}, {0x08, set_screensaver, 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}, {0x0b, set_wifichancycle, 1, true}, {0x0c, set_blescantime, 1, true},
{0x0d, set_vendorfilter, 1, false}, {0x0e, set_blescan, 1, true}, {0x0d, set_vendorfilter, 1, false}, {0x0e, set_blescan, 1, true},
{0x0f, set_wifiant, 1, true}, {0x10, set_rgblum, 1, true}, {0x0f, set_wifiant, 1, true}, {0x10, set_rgblum, 1, true},

134
src/reset.cpp Normal file
View File

@ -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;
}