Compare commits

..

2 Commits

Author SHA1 Message Date
Thaddeus Hughes
fff1295862 TODOing 2026-03-11 21:46:52 -05:00
Thaddeus Hughes
123ddc2688 adding todos 2026-03-11 20:31:36 -05:00
5 changed files with 316 additions and 34 deletions

75
TODO.md
View File

@@ -1,20 +1,55 @@
# TODO
- [test] Seamless crashing
- crashes need to not cause RTC to lose time
- the remaining_distance needs to be unaffected
- the equivalent of a try-catch block on the whole program
- this should also make a log
- [x] Logtool: python tool that shows logs
-[x] needs to support both opening a log.bin and streaming from http://ip-address-or-hostname/log
-[x] needs to have a CLI table output
-[test] needs to have a GUI output (matplotlib)
- [test] Refactor; make sure everything adheres to naming conventions
- [test] Renaming wifi (should reboot the wifi/web comms to take effect)
- [x] Make sure external RTC crystal is actually in use
- [x] Warn if time is de-synced from client by more than 5 minutes
- [x] Bluetooth pairing
- [ ] WiFi Network Connection
- add entries for wifi network ssid/password
- try to connect to the wifi network first
- if that fails then broadcast ad-hoc network like currently
- [ ] Hard Reset
# SC-F001 Firmware — TODO
- [ ] sdkconfig audit
- [ ] Enable `CONFIG_ESP_TASK_WDT_PANIC=y` (required for OTA rollback reset counter to work on WDT hangs)
- [ ] Verify `CONFIG_FREERTOS_CHECK_STACKOVERFLOW=2` is set (currently canary — confirmed)
- [ ] Verify `CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT` is set (currently set — confirmed)
- [ ] Confirm brownout detector level (~2.43V) is appropriate for 12V battery system with regulator
- [ ] Research sdkconfig management best practices; document in CLAUDE.md
- [ ] Fix managed_components: remove unused deps, pin versions in `idf_component.yml`; document in CLAUDE.md
- [ ] OTA rollback via consecutive-reset counter
- [ ] Add `RTC_DATA_ATTR uint8_t reset_counter` — increment on boot, clear after successful health check
- [ ] On counter ≥ 5, call `esp_ota_mark_app_invalid_rollback_and_reboot()`
- [ ] After POST passes and FSM starts, call `esp_ota_mark_app_valid_cancel_rollback()`
- [ ] Decide what "health check passes" means (POST passes? 30s uptime? first successful FSM cycle?)
- [ ] Critical init failures (ADC, storage, log, I2C, FSM, sensors) should `esp_restart()` — this feeds the OTA rollback reset counter
- [ ] Non-critical init failures (wifi, webserver, RF, BT) should log a `LOG_TYPE_ERROR` entry and attempt retry
- [ ] WiFi/BT already have restart paths (`webserver_restart_wifi()`, `bt_hid_resume()`) — wire these into a retry-on-failure path at boot, not just soft idle exit
- [ ] Power-on self-test (POST) — run after all inits, before FSM starts; log results; feed OTA health check
- [ ] ADC: read all 4 channels twice with short delay, flag if frozen or out of range (battery 525V, currents 0150A)
- [ ] I2C: verify TCA9555 responds (read port 0)
- [ ] Flash: write-read-verify test on last sector of storage partition
- [ ] Parameter validation
- [ ] Add per-param bounds to `PARAM_LIST` macro (min, max, flags)
- [ ] NaN/Inf → reset to default; out-of-range → clamp to min/max
- [ ] Enforce validation inside `commit_params()` (covers both `storage_init()` load and `/set` POST)
- [ ] Audit for anywhere params are set without an immediate `commit_params()` call
- [ ] Audit abandoned parameters (e.g. jack current) — add comments marking them deprecated
- [ ] Factory reset: erase entire storage partition (not just params), require 10s button hold, LED indication (flash all → hold solid once triggered)
- [ ] Ensure RTC_DATA_ATTR variables survive panics/WDT resets
- [ ] Verify `sync_unix_us`, `sync_rtc_us`, `rtc_set` (time) are not corrupted by any init path
- [ ] Verify `remaining_distance`, `fsm_error` (FSM state) are not zeroed except by intentional reset
- [ ] Verify `log_head_offset`, `log_tail_offset` stay consistent after crash (no partial writes)
- [ ] Measure flash log write duration (bracket with `esp_timer_get_time()`, compare to WDT timeout of 5s)
- [ ] WiFi STA mode with event-group signaling
- [ ] Try connecting to saved STA network first, fall back to softAP on failure/timeout
- [ ] Add `EventGroupHandle_t` with `WIFI_READY_BIT` (set when STA connected or softAP up) and `BT_READY_BIT` (set when BT scan task starts)
- [ ] Replace blind 500ms `vTaskDelay` on alarm wake with `xEventGroupWaitBits()` + timeout
- [ ] Use same event group in `soft_idle_exit()` path
- [ ] Verify `sensors_init()` placement and ISR safety
- [ ] Confirm `sensors_init()` is safe to call from `app_main()` (research says yes — creates queue + installs ISR service, no task-context dependency)
- [ ] Decide: move to main.c (simpler) or keep in `control_task()` (current) — either way, remove the dead commented-out call in main.c and add a clarifying comment
- [ ] Audit all ISRs are IRAM-safe: no `ESP_LOGx`, `printf`, `malloc`, or flash access — only `xQueueSendFromISR()`
- [ ] Handle `sensors_init()` failure as critical (→ reboot)
- [ ] Confirm whether external RTC crystal can be dropped (device never enters deep sleep now) — if yes, remove `rtc_xtal_init()` and related sdkconfig entries; if no, document why it must stay
- [ ] Remove `rtc_wakeup_cause()` call (informational only, no longer needed)
- [ ] Confirm `rtc_check_shutdown_timer()` uses signed subtraction — then remove the esp_timer overflow TODO comment (int64_t overflows after 292K years)
- [ ] Extract pure logic (e-fuse thermal model, param serialization, sensor debounce) into host-testable modules with Unity/CMock
- [ ] UART integration test framework: Python runner + ESP-side test commands
- [test] Logtool GUI output (matplotlib)
- [test] Verify naming convention adherence across codebase
- [test] Verify WiFi SSID rename triggers comms reboot
- [ ] Documentation restructure
- [ ] Move project/hardware documentation from CLAUDE.md → README.md; keep CLAUDE.md for AI-specific instructions and conventions only
- [ ] Document all FreeRTOS tasks and priorities in README.md
- [ ] Add terse comments to FSM state transitions in `control_fsm.c` (focus on "why", not "what")

224
TODO.verbose.md Normal file
View File

@@ -0,0 +1,224 @@
# SC-F001 Firmware — TODO Tracker
Extracted from `// TODO` comments across the codebase plus legacy items. Excludes third-party managed components.
---
## Legacy Items (from previous TODO.md)
- [test] Seamless crashing — crashes need to not cause RTC to lose time; remaining_distance unaffected; equivalent of try-catch on whole program; should also make a log
- [test] Logtool GUI output (matplotlib)
- [test] Refactor; make sure everything adheres to naming conventions
- [test] Renaming wifi (should reboot the wifi/web comms to take effect)
- [ ] WiFi Network Connection — try STA first, fall back to softAP
- [ ] Hard Reset
---
## 1. Reliability & Crash Recovery
| File | Line | TODO |
|------|------|------|
| `main.c` | 192 | Make sure that this is "crash proof" |
| `main.c` | 193 | OTA rollback (triggered how? preferably with hardware... or if there are 5 resets in a row. also need way to nuke the storage partition or safe boot) |
| `main.c` | 194 | (maybe) recovery partition that allows uploading firmware |
| `storage.c` | 409 | WIPE ENTIRE PARTITION (factory reset only resets params, doesn't erase log) |
**Commentary:**
- OTA rollback is critical for field-deployed devices. ESP-IDF has built-in rollback support via `esp_ota_mark_app_valid_cancel_rollback()` — the app marks itself valid after a health check, otherwise the bootloader reverts on next reboot. This is the standard approach; a "5 resets in a row" counter can be stored in RTC_DATA_ATTR or an NVS counter.
- A recovery partition (minimal firmware with just WiFi + OTA upload) is a strong safety net. ESP-IDF's factory/OTA partition scheme supports this natively — the factory partition acts as the recovery image.
- Factory reset should absolutely erase the log partition. A `esp_partition_erase_range()` over the full log region is straightforward and should be added.
- "Crash proof" is vague — consider defining what this means concretely: e.g., no stuck relays after watchdog reset (already handled by TCA9555 power-on defaults), no corrupted params (CRC32 already protects), log head/tail consistency after power loss.
**Path Forwards:**
1. Implement a 5 reset in a row counter in RTC_DATA_ATTR that will rollback to the previous
2. Make the factory reset erase the storage partition. It should be triggered by the button being held on power on for at least 10 seconds, and should give LED indication (flash all LEDs off and on, then hold on once the reset is triggered)
3. crashproofing should mainly keep any RTC_DATA_ATTR variables from getting reset if anything panics - namely no losing time, no losing remaining position (other RTC_DATA_ATTR vars less important)
---
## 2. Error Handling & Logging
| File | Line | TODO |
|------|------|------|
| `main.c` | 174 | Do things with errors (put in real log? then reset. "assert with LOGE"?) |
| `main.c` | 228 | Seriously, log all the errors on bluetooth |
| `main.c` | 178 | Figure out how long logging takes (for reference, and comp to wdt) |
**Commentary:**
- Currently, init failures are logged but execution continues — this is the right pattern for a field device (degrade gracefully), but errors should be persisted. Use the existing `LOG_TYPE_ERROR` entry type to write a structured error log entry on each init failure, including the module ID and error code.
- BT errors are particularly important because BLE stacks fail silently in many edge cases (connection drops, service discovery timeouts, pairing failures). At minimum, log connection/disconnection events and HID report parse failures.
- Logging duration: flash writes on ESP32 typically take 5-20ms per sector erase + write. With a 10s WDT and 20ms FSM tick, this is fine, but verify empirically with `esp_timer_get_time()` bracketing. Consider using the async log queue (already in architecture) to keep flash writes off the FSM task.
**Path Forwards:**
1. wifi, webserver, rf, and bluetooth failures are acceptable gracefully, though they should try to start again if it still makes sense. All other failures are not acceptable and should cause a system reset.
2. Need to actually test and time the logging duration.
---
## 3. Safety & Robustness Audits
| File | Line | TODO |
|------|------|------|
| `main.c` | 113 | Check wdt stuff |
| `main.c` | 114 | Stack Overflow Detection |
| `main.c` | 273 | Make sure all ISRs are clean (very tight, no blocking functions) |
| `control_fsm.c` | 99 | Make sure this is threadsafe (fsm_request / xQueueSend) |
**Commentary:**
- **WDT:** The 10s timeout is already configured. Verify every task calls `esp_task_wdt_reset()` within its loop. Consider enabling `CONFIG_ESP_TASK_WDT_PANIC=y` in sdkconfig so a WDT timeout triggers a core dump rather than a silent reset.
- **Stack overflow:** Enable `CONFIG_FREERTOS_CHECK_STACKOVERFLOW=2` (canary method) in sdkconfig. This catches overflows at context switch time. Also use `uxTaskGetStackHighWaterMark()` during development to right-size stacks.
- **ISR audit:** ESP-IDF provides `ESP_INTR_FLAG_IRAM` for ISR placement. Ensure no ISR calls `ESP_LOGx`, `printf`, `malloc`, or any flash-access function. The sensor ISR should only do `xQueueSendFromISR()`.
- **Thread safety of `fsm_request`:** `xQueueSend` is inherently thread-safe in FreeRTOS — it's designed for cross-task and ISR-to-task communication. This TODO can likely be closed. Just confirm `fsm_cmd_queue` is created before any caller can invoke `fsm_request()`.
**Path Forwards:**
1. Make the necessary changes to sdkconfig
2. Look at ISRs (I actually don't think we have any but double check)
---
## 4. Power Management & Sleep
| File | Line | TODO |
|------|------|------|
| `main.c` | 208 | Is this reasonable now that we eliminated deep sleep? (solar FSM call) |
| `main.c` | 210 | Do a 12V check and enter deep sleep if there's a problem |
| `main.c` | 365 | Will esp_timer overflow? Handle overflow if needed |
**Commentary:**
- **Solar FSM after eliminating deep sleep:** If deep sleep is no longer used, `solar_run_fsm()` still makes sense — it controls GPIO26 (bulk/float charge switching). Review whether the FLOAT→BULK transitions still trigger correctly without the deep sleep wake cycle.
- **12V check:** A critical low-voltage protection. If battery voltage is dangerously low (below the charger's cutoff), the ESP32 should enter deep sleep to let the panel charge without load. This prevents brown-out damage to flash. Threshold should be configurable via a parameter (it already has `LOW_PROTECTION_V`).
- **`esp_timer_get_time()` overflow:** Returns `int64_t` microseconds. It overflows after ~292,000 years — this is a non-issue. This TODO can be closed after confirming `rtc_check_shutdown_timer()` uses signed subtraction.
**Path Forwards:**
1. Keep solar FSM just in the main loop
2. Don't do any low-voltage checking
3. Confirm that rtc_check_shutdown_timer() uses signed subtraction.
---
## 5. Startup & Initialization Hygiene
| File | Line | TODO |
|------|------|------|
| `main.c` | 115 | Remove XTAL crystal stuff |
| `main.c` | 120 | `rtc_wakeup_cause()` shouldn't be needed anymore |
| `main.c` | 125 | How many tasks do we have? |
| `main.c` | 232 | `sensors_init()` — Why is this off? |
| `control_fsm.c` | 185 | Why is `sensors_init()` here rather than in main? |
**Commentary:**
- **XTAL removal:** The CLAUDE.md documents the crystal bootstrap workaround as essential for RTC accuracy. Don't remove `rtc_xtal_init()` unless you've confirmed the hardware no longer uses the external crystal — removing it would silently degrade RTC accuracy to ±5%.
- **`rtc_wakeup_cause()`:** If it's purely informational logging, it's harmless. Either delete it or keep it — it's one log line at boot.
- **Task count:** Document the task list: main loop (implicit), `control_task`, UART task, RF 433 task, BT HID task, HTTP server workers. Use `uxTaskGetNumberOfTasks()` at boot to log the count.
- **`sensors_init()` location:** It's called inside `control_task()` (line 185) and commented out in `main.c` (line 232). This is intentional — sensors are initialized in the FSM task context because the ISR handlers need to send to queues created in that scope. The comment in main.c should be removed and the one in control_fsm.c clarified.
**Path Forwards:**
1. Confirm that we can stop using the RTC and just use the internal crystal (never go into low power state)
2. Remove wakeup cause
3. Document a list of tasks and put in README.md
4. Double check that sensors_init() shouldn't be called in main. Make sure that the error code from it is handled appropriately (it MUST init properly; if it doesn't, reboot)
---
## 6. Soft Idle & Wake Behavior
| File | Line | TODO |
|------|------|------|
| `main.c` | 243 | Critique & confirm what we do in idle |
| `main.c` | 256 | Do a hard wait until wifi and bluetooth come up, not just blindly wait; might be better to be non-blocking |
**Commentary:**
- **Idle behavior:** The soft idle mode polls at 5s via direct GPIO (no I2C). This saves power but means TCA9555 button state is stale. Confirm that the only wake sources (GPIO13 button, RTC alarm) don't depend on I2C. The current design looks correct.
- **WiFi/BT wake wait:** The 500ms `vTaskDelay` is fragile — WiFi association can take 1-5s depending on the AP. Use event groups: `wifi_event_group` with a `CONNECTED_BIT`, wait with `xEventGroupWaitBits()` and a timeout. This is the standard ESP-IDF pattern. For BT, the scan is already async so it doesn't need blocking.
**Path Forwards:**
1. Do a hard wait until wifi and bluetooth come up rather than blindly. Needs to be non-blocking. Need bluetooth to finish initting, and wifi to have connected to a network or brought up the softap.
---
## 7. Testing & Verification
| File | Line | TODO |
|------|------|------|
| `main.c` | 214 | Test strategy!!! (software verification, and unit bringup) |
| `main.c` | 215 | A→D bringup; sanity check (sum up all inputs, wait 5ms, sum again, make sure there is a change (not frozen)) |
**Commentary:**
- **Test strategy:** For embedded firmware, consider three layers:
1. **Host-side unit tests** — extract pure logic (e-fuse thermal model, param serialization, log format) into testable modules. Run with Unity or CMock on the host.
2. **On-target POST** — a power-on self-test routine that validates ADC readings are in-range, I2C responds, flash is accessible. Run once at boot, log results.
3. **Integration tests** — scripted UART commands that exercise the FSM cycle end-to-end. The existing `log_test.c` is a start.
- **ADC sanity check:** Good idea. Read all ADC channels twice with a short delay; if any channel returns identical values both times (especially the current sense channels, which should have noise), flag it. This catches stuck ADC mux, disconnected sense resistors, or frozen DMA.
**Path Forwards:**
1. Make pure logic for sensors, FSMs, e-fusing. This is an entire project.
2. Make a POST: that would include ADC, I2C, flash accessibility
3. Make a UART integration test, both a python runner, and the requesite ESP code
---
## 8. Storage & Parameters
| File | Line | TODO |
|------|------|------|
| `storage.h` | 7 | Sanity check that the EEPROM is working (sacrifice sector 0?) |
| `storage.h` | 57 | Bounds checking / constraints (especially no division by zero, no NaNs, no infs) |
| `storage.h` | 58 | Abandoned parameters (esp. jack current) |
**Commentary:**
- **Flash health check:** A simple write-read-verify test on a dedicated test sector at boot is a good idea. Alternatively, rely on the CRC32 check already protecting the param sector — if CRC fails, you know flash is degraded.
- **Parameter validation is the highest-priority item here.** Any f32 parameter used as a divisor (e.g., `DRIVE_KT`, `DRIVE_KE`, `EFUSE_INOM_*`) must be validated on load: reject NaN, Inf, and zero. Clamp to sane ranges. A `param_validate()` function called after `storage_init()` and after any `/set` POST would prevent field bricking from a bad parameter write.
- **Abandoned parameters:** Audit the PARAM_LIST. If `JACK_CURRENT` or similar params are no longer used by any code path, remove them to avoid confusion. Verify with grep first — sometimes params are only referenced from the web UI.
**Path Forwards:**
1. Utilize the last sector of the flash as a read-write-verify test
2. Add bounds in the PARAMS_LIST. It should accept a function or macro with arguments. Per-parameter we might want different min/max. and some parameters we will want to check and ensure it is NaN/inf. If Nan/Inf/etc set to default, otherwise clamp to min/max
3. Check in code - is there anywhere we don't immediately commit after setting a parameter? add bounds checking to the commit. This should do it
4. Audit abandoned parameters. Don't outright remove them just put a comment for now
---
## 9. Build & Configuration
| File | Line | TODO |
|------|------|------|
| `main.c` | 217 | Make sure sdkconfig is sane. Make notes. |
| `main.c` | 218 | Fix managed_components |
**Commentary:**
- **sdkconfig audit — key settings to verify:**
- `CONFIG_ESP_TASK_WDT_PANIC=y` (WDT triggers panic + core dump, not silent reset)
- `CONFIG_FREERTOS_CHECK_STACKOVERFLOW=2` (canary-based detection)
- `CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT` (print backtrace then reboot)
- `CONFIG_PARTITION_TABLE_CUSTOM=y` with correct factory/OTA layout
- `CONFIG_RTC_CLK_SRC_EXT_CRYS=y` (already set per CLAUDE.md)
- Confirm brownout detector level matches your minimum operating voltage
- **managed_components:** ESP-IDF's component manager can cause build reproducibility issues. Pin exact versions in `idf_component.yml`. Consider vendoring critical components (mdns, littlefs, tca95x5) into the repo if version drift causes problems.
**Path Forwards:**
1. Research best practices to manage sdkconfig; document in CLAUDE.md
2. Fix managed_components and remove anything that is not being utilized and then make idf.py happy; document in CLAUDE.md
3. Apply best practices to manage sdkconfig
---
## 10. Documentation
| File | Line | TODO |
|------|------|------|
| `control_fsm.c` | 9 | Comment, and even better, produce a README for this. |
**Commentary:**
- The CLAUDE.md already serves as comprehensive FSM documentation. Adding inline comments to `control_fsm.c` describing each state transition's guard conditions and timing rationale would be more valuable than a separate README. Focus comments on the "why" — the state names and relay outputs are self-documenting for the "what."
**Path Forwards:**
1. Copy FSM documentation to README.md
2. Add comments (terse but helpful) to the FSM
---
## 11. OTHER
**Path Forwards:**
1. Fix docs; CLAUDE.md should be claude-specific instructions and such; README.md should contain everything else.

View File

@@ -4,6 +4,9 @@
* Created on: Nov 10, 2025
* Author: Thad
*/
// TODO: Comment, and even better, produce a README for this.
#include "control_fsm.h"
#include "esp_task_wdt.h"
@@ -93,6 +96,7 @@ void fsm_request(fsm_cmd_t cmd)
rtc_reset_shutdown_timer(); // any accepted command extends the wake period
if (fsm_cmd_queue != NULL)
xQueueSend(fsm_cmd_queue, &cmd, 0); // safe from any context
// TODO: Make sure this is threadsafe
}
int8_t fsm_get_current_progress(int8_t denominator) {
@@ -178,7 +182,7 @@ void control_task(void *param) {
const TickType_t xFrequency = pdMS_TO_TICKS(20);
enabled = true;
sensors_init();
sensors_init(); // TODO: Why is this *here* rather than in main?
while (enabled) {
vTaskDelayUntil(&xLastWakeTime, xFrequency);

View File

@@ -26,8 +26,6 @@ esp_err_t send_bat_log() {
uint8_t entry[12] = {};
// Pack 64-bit timestamp into bytes 1-8
uint64_t be_timestamp = rtc_get_ms();
memcpy(&entry[0], &be_timestamp, 8);
@@ -111,16 +109,21 @@ void app_main(void) {esp_task_wdt_add(NULL);
ESP_LOGI(TAG, "Version: %s", FIRMWARE_VERSION);
ESP_LOGI(TAG, "Branch: %s", FIRMWARE_BRANCH);
ESP_LOGI(TAG, "Built: %s", BUILD_DATE);
// TODO: Check wdt stuff
// TODO: Stack Overflow Detection
// TODO: Remove XTAL crystal stuff
if (rtc_xtal_init() != ESP_OK) ESP_LOGE(TAG, "RTC FAILED");
rtc_restore_time(); // Recover time from RTC domain if we crashed
// Say hello; turn on the lights
rtc_wakeup_cause(); // log wakeup cause (informational only)
rtc_wakeup_cause(); // log wakeup cause (informational only) // TODO: Shouldnt be needed anymore
if (i2c_init() != ESP_OK) ESP_LOGE(TAG, "I2C FAILED");
i2c_set_relays((relay_port_t){.raw=0});
drive_leds(LED_STATE_BOOTING);
// TODO: How many tasks do we have?
// Check for factory reset condition: Cold boot (power-on/ext-reset) + button held
esp_reset_reason_t boot_reset_reason = esp_reset_reason();
@@ -168,10 +171,12 @@ void app_main(void) {esp_task_wdt_add(NULL);
}
// Every boot we load parameters and monitor solar, no matter what
// TODO: Do things with errors (put in real log? then reset. "assert with LOGE"?)
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");
// TODO: figure out how long logging takes (for reference, and comp to wdt)
esp_reset_reason_t reset_reason = esp_reset_reason();
esp_sleep_wakeup_cause_t wake_cause = esp_sleep_get_wakeup_cause();
@@ -184,6 +189,9 @@ void app_main(void) {esp_task_wdt_add(NULL);
log_write(boot_entry, sizeof(boot_entry), LOG_TYPE_BOOT);
}
// TODO: make sure that this is "crash proof"
// TODO: OTA rollback (triggered how? preferably with hardware... or if there are 5 resets in a row [check bootloader?]. also need way to nuke the storage partition or safe boot)
// TODO: (maybe) recovery partition that allows uploading firmware
// Write a crash log entry if we rebooted unexpectedly
if (reset_reason == ESP_RST_PANIC ||
reset_reason == ESP_RST_INT_WDT ||
@@ -197,11 +205,17 @@ void app_main(void) {esp_task_wdt_add(NULL);
log_write(crash_entry, sizeof(crash_entry), LOG_TYPE_CRASH);
}
// TODO: is this reasonable now that we eliminated deep sleep?
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();
// TODO: test strategy!!! (software verification, and unit bringup)
// TODO: A->D bringup; sanity check (sum up all inputs, wait 5ms, sum again, make sure there is a change (not frozen))
// TODO: make sure sdkconfig is sane. Make notes, have claude figure this out properly
// TODO: fix managed_components
//send_log();
@@ -210,26 +224,23 @@ void app_main(void) {esp_task_wdt_add(NULL);
/*** FULL BOOT — always, every boot ***/
if (uart_init() != ESP_OK) ESP_LOGE(TAG, "UART FAILED");
//if (power_init() != ESP_OK) ESP_LOGE(TAG, "POWER FAILED");
// TODO: Seriously, log all the errors on bluetooth
if (rf_433_init() != ESP_OK) ESP_LOGE(TAG, "RF FAILED");
if (bt_hid_init() != ESP_OK) ESP_LOGE(TAG, "BT HID FAILED");
if (fsm_init() != ESP_OK) ESP_LOGE(TAG, "FSM FAILED");
//if (sensors_init() != ESP_OK) ESP_LOGE(TAG, "SENSORS FAILED");
//if (sensors_init() != ESP_OK) ESP_LOGE(TAG, "SENSORS FAILED"); // TODO: Why is this off?
if (webserver_init() != ESP_OK) ESP_LOGE(TAG, "WEBSERVER FAILED");
/*** MAIN LOOP ***/
TickType_t xLastWakeTime = xTaskGetTickCount();
const TickType_t xFrequency = pdMS_TO_TICKS(50);
/*while(true) {
ESP_LOGI(TAG, "TICK");
vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(1000));
esp_task_wdt_reset();
}*/
while(true) {
vTaskDelayUntil(&xLastWakeTime, xFrequency);
/* In soft idle: slow poll (5s) via direct GPIO, no I2C. */
// TODO: Critique & confirm what we do in idle
if (soft_idle_is_active()) {
//vTaskDelay(pdMS_TO_TICKS(1000));
if (soft_idle_button_raw()) {
@@ -242,6 +253,7 @@ void app_main(void) {esp_task_wdt_add(NULL);
soft_idle_exit();
xLastWakeTime = xTaskGetTickCount();
vTaskDelay(pdMS_TO_TICKS(500));
// TODO: do a hard wait until wifi and bluetooth come up, not just blindly wait; might be better to be non-blocking
fsm_request(FSM_CMD_START);
rtc_schedule_next_alarm();
}
@@ -257,6 +269,8 @@ void app_main(void) {esp_task_wdt_add(NULL);
rtc_reset_shutdown_timer();
soft_idle_exit();
}
// TODO: Make sure all ISRs are clean (very tight, no blocking functions)
switch (fsm_get_state()) {
case STATE_IDLE:
@@ -348,7 +362,7 @@ void app_main(void) {esp_task_wdt_add(NULL);
}
solar_run_fsm();
rtc_check_shutdown_timer();
rtc_check_shutdown_timer(); // TODO: Will esp timer overflow? Handle overflow if needed (this used to be handled by the fact that we were in deep sleep)
esp_task_wdt_reset();
}
}

View File

@@ -4,6 +4,8 @@
#include <stdint.h>
#include "esp_err.h"
// TODO: Sanity check that the EEPROM is working (sacrifice sector 0?)
// ============================================================================
// FLASH LAYOUT CONSTANTS
// ============================================================================
@@ -52,6 +54,9 @@ typedef struct {
// ============================================================================
// TODO: Bounds checking / constraints (especially no division by zero, no NaNs, no infs)
// TODO: abandoned parameters (esp. jack current)
#define PARAM_LIST \
PARAM_DEF(BOOT_TIME, i32, 0, "us") \
PARAM_DEF(NUM_MOVES, u32, 0, "") \