diff --git a/TODO.md b/TODO.md index b315d6c..d1bf32e 100644 --- a/TODO.md +++ b/TODO.md @@ -9,5 +9,7 @@ - needs to have a CLI table output - needs to have a GUI output (matplotlib) - [ ] Refactor; make sure everything adheres to naming conventions -- [ ] Bluetooth pairing -- [ ] Renaming wifi (should reboot the wifi/web comms to take effect) \ No newline at end of file +- [ ] Renaming wifi (should reboot the wifi/web comms to take effect) +- [ ] Make sure external RTC crystal is actually in use +- [ ] Warn if time is de-synced from client by more than 5 minutes +- [ ] Bluetooth pairing \ No newline at end of file diff --git a/main/control_fsm.h b/main/control_fsm.h index c153688..7d828dc 100644 --- a/main/control_fsm.h +++ b/main/control_fsm.h @@ -42,7 +42,8 @@ typedef enum { STATE_CALIBRATE_DRIVE_DELAY, STATE_CALIBRATE_DRIVE_MOVE } fsm_state_t; -#define LOG_TYPE_BAT 100 +#define LOG_TYPE_BAT 100 +#define LOG_TYPE_CRASH 101 typedef enum { RELAY_SENSORS = 0, diff --git a/main/main.c b/main/main.c index 3ccef81..2a8f437 100644 --- a/main/main.c +++ b/main/main.c @@ -1,4 +1,5 @@ #include "esp_task_wdt.h" +#include "esp_system.h" #include "i2c.h" #include "log_test.h" #include "storage.h" @@ -109,7 +110,8 @@ void app_main(void) {esp_task_wdt_add(NULL); //run_all_log_tests(); if (rtc_xtal_init() != ESP_OK) ESP_LOGE(TAG, "RTC FAILED"); - + rtc_restore_time(); // Restore time from RTC backup if we crashed + // Say hello; turn on the lights esp_sleep_wakeup_cause_t cause = rtc_wakeup_cause(); if (i2c_init() != ESP_OK) ESP_LOGE(TAG, "I2C FAILED"); @@ -171,9 +173,24 @@ void app_main(void) {esp_task_wdt_add(NULL); if (adc_init() != ESP_OK) ESP_LOGE(TAG, "ADC FAILED"); if (storage_init() != ESP_OK) ESP_LOGE(TAG, "STORAGE FAILED"); if (log_init() != ESP_OK) ESP_LOGE(TAG, "LOG FAILED"); + + // Write a crash log entry if we rebooted unexpectedly + esp_reset_reason_t reset_reason = esp_reset_reason(); + if (reset_reason == ESP_RST_PANIC || + reset_reason == ESP_RST_INT_WDT || + reset_reason == ESP_RST_TASK_WDT || + reset_reason == ESP_RST_WDT) { + ESP_LOGW(TAG, "Crash detected! Reset reason: %d", reset_reason); + uint8_t crash_entry[9] = {}; + uint64_t ts = rtc_get_ms(); + memcpy(&crash_entry[0], &ts, 8); + crash_entry[8] = (uint8_t)reset_reason; + log_write(crash_entry, sizeof(crash_entry), LOG_TYPE_CRASH); + } + if (solar_run_fsm() != ESP_OK) ESP_LOGE(TAG, "SOLAR FAILED"); // TODO: Do a 12V check and enter deep sleep if there's a problem - + send_bat_log(); @@ -315,9 +332,10 @@ void app_main(void) {esp_task_wdt_add(NULL); fsm_request(FSM_CMD_START); rtc_schedule_next_alarm(); } - + solar_run_fsm(); - + rtc_save_time(); // Keep RTC backup fresh so crashes don't lose time + rtc_check_shutdown_timer(); esp_task_wdt_reset(); } diff --git a/main/rtc.c b/main/rtc.c index f52fb35..6fe3b9a 100644 --- a/main/rtc.c +++ b/main/rtc.c @@ -34,9 +34,10 @@ uint64_t last_activity_tick = 0; -// RTC_DATA_ATTR keeps this var in RTC memory; persists across sleeps (but not across boots) +// RTC_DATA_ATTR keeps these in RTC memory; persists across deep sleep AND software resets (panics, WDT) RTC_DATA_ATTR int64_t next_alarm_time_s = -1; RTC_DATA_ATTR bool rtc_set = false; +RTC_DATA_ATTR int64_t rtc_backup_s = 0; // Crash-safe time snapshot bool rtc_is_set() { return rtc_set; } @@ -94,10 +95,25 @@ void rtc_set_s(int64_t tv_sec) { rtc_set = true; settimeofday(&(struct timeval){.tv_sec = tv_sec, .tv_usec=0}, NULL); + rtc_backup_s = tv_sec; solar_reset_fsm(); rtc_schedule_next_alarm(); } +void rtc_save_time(void) +{ + if (rtc_set) + rtc_backup_s = rtc_get_s(); +} + +void rtc_restore_time(void) +{ + if (rtc_set && rtc_backup_s > 0) { + settimeofday(&(struct timeval){.tv_sec = rtc_backup_s, .tv_usec = 0}, NULL); + ESP_LOGI("RTC", "Time restored from crash backup: %lld", (long long)rtc_backup_s); + } +} + int64_t rtc_get_ms(void) { struct timeval tv; diff --git a/main/rtc.h b/main/rtc.h index 1930088..b4c6ba0 100644 --- a/main/rtc.h +++ b/main/rtc.h @@ -43,6 +43,9 @@ int64_t rtc_get_s (void); int64_t rtc_get_ms(void); void rtc_set_s(int64_t); +void rtc_save_time(void); // Snapshot current time to RTC memory (call periodically) +void rtc_restore_time(void); // Restore time from RTC backup after a crash reboot + void rtc_schedule_next_alarm(void); int64_t rtc_get_next_alarm_s();