move nvs init around, more graceful bt/wifi bringup/down, led indicatorrs

This commit is contained in:
Thaddeus Hughes
2026-03-11 10:05:13 -05:00
parent f4077e5e26
commit af02fbb117
7 changed files with 101 additions and 52 deletions

View File

@@ -60,7 +60,8 @@
// ---------------------------------------------------------------------------
#define TAG "BT_HID"
#define BT_HID_SCAN_DURATION_S 3 /* ceiling only — scan stops early on first HID hit */
#define BT_HID_SCAN_DURATION_S 3
#define BT_HID_MIN_RSSI (-70) /* dBm — ignore devices weaker than this */
#define BT_HID_RECONNECT_MS 2000
#define BT_HID_BOND_TIMEOUT_MS 5000 /* wait for saved device before scanning */
#define BT_HID_CONNECT_WAIT_MS 5000 /* wait after open() before next loop */
@@ -245,6 +246,9 @@ static void hidh_callback(void *handler_args,
nvs_save_bda(bda, s_connect_addr_type);
} else {
ESP_LOGE(TAG, "OPEN failed, status=%d", p->open.status);
/* Free the failed device handle — not doing so leaks a BT
* resource and can block future connection attempts. */
esp_hidh_dev_free(p->open.dev);
}
break;
}
@@ -342,6 +346,15 @@ static void ble_gap_event_handler(esp_gap_ble_cb_event_t event,
memcpy(name, name_d, copy);
}
if (param->scan_rst.rssi < BT_HID_MIN_RSSI) {
ESP_LOGD(TAG, "SCAN %02x:%02x:%02x:%02x:%02x:%02x RSSI:%d '%s' (too weak, skipping)",
param->scan_rst.bda[0], param->scan_rst.bda[1],
param->scan_rst.bda[2], param->scan_rst.bda[3],
param->scan_rst.bda[4], param->scan_rst.bda[5],
param->scan_rst.rssi, name);
break;
}
ESP_LOGI(TAG, "SCAN %02x:%02x:%02x:%02x:%02x:%02x RSSI:%d '%s' <<< HID",
param->scan_rst.bda[0], param->scan_rst.bda[1],
param->scan_rst.bda[2], param->scan_rst.bda[3],
@@ -352,9 +365,6 @@ static void ble_gap_event_handler(esp_gap_ble_cb_event_t event,
param->scan_rst.ble_addr_type,
name,
param->scan_rst.rssi);
/* Stop scanning immediately — we have what we need. */
esp_ble_gap_stop_scanning();
break;
}

View File

@@ -229,6 +229,28 @@ void app_main(void) {esp_task_wdt_add(NULL);
while(true) {
vTaskDelayUntil(&xLastWakeTime, xFrequency);
/* In soft idle: slow poll (5s) via direct GPIO, no I2C. */
if (soft_idle_is_active()) {
//vTaskDelay(pdMS_TO_TICKS(1000));
if (soft_idle_button_raw()) {
rtc_reset_shutdown_timer();
soft_idle_exit();
i2c_poll_buttons(); /* sync TCA9555 state after idle */
xLastWakeTime = xTaskGetTickCount();
}
if (rtc_alarm_tripped()) {
soft_idle_exit();
xLastWakeTime = xTaskGetTickCount();
vTaskDelay(pdMS_TO_TICKS(500));
fsm_request(FSM_CMD_START);
rtc_schedule_next_alarm();
}
solar_run_fsm();
rtc_check_shutdown_timer();
esp_task_wdt_reset();
continue;
}
i2c_poll_buttons();
if (i2c_get_button_state(0)) {
@@ -248,22 +270,22 @@ void app_main(void) {esp_task_wdt_add(NULL);
} else if (i2c_get_button_ms(0) > 100){
drive_leds(LED_STATE_START1);
} else {
/*if (
if (
rtc_is_set() &&
!efuse_is_tripped(BRIDGE_JACK) &&
!efuse_is_tripped(BRIDGE_AUX) &&
!efuse_is_tripped(BRIDGE_DRIVE) &&
efuse_get(BRIDGE_JACK)==EFUSE_OK &&
efuse_get(BRIDGE_AUX)==EFUSE_OK &&
efuse_get(BRIDGE_DRIVE)==EFUSE_OK &&
fsm_get_error() == ESP_OK
) {
drive_leds(LED_STATE_AWAKE);
} else {
drive_leds(LED_STATE_ERROR);
}*/
}
int8_t state = 0b001;
/*int8_t state = 0b001;
if (get_is_safe()) state |= 0b010;
if (get_sensor(SENSOR_SAFETY)) state |= 0b100;
i2c_set_led1(state);
i2c_set_led1(state);*/
}
// when not actively moving we log at a low frequency (every 120s)
@@ -321,12 +343,6 @@ void app_main(void) {esp_task_wdt_add(NULL);
if (rtc_alarm_tripped()) {
bool was_idle = soft_idle_is_active();
soft_idle_exit();
if (was_idle) {
// Give WiFi softAP time to come up before movement begins
vTaskDelay(pdMS_TO_TICKS(500));
}
fsm_request(FSM_CMD_START);
rtc_schedule_next_alarm();
}

View File

@@ -63,7 +63,11 @@ static void rf_433_receiver_task(void* param) {
rmt_rx_done_event_data_t rx_data;
rmt_receive_config_t rx_config = {
.signal_range_min_ns = 2000,
/* Hardware filter max on ESP32 is ~3187 ns (8-bit APB counter).
* Filters sub-3µs glitches; can't filter longer noise pulses in HW.
* Buffer overflow from other 433 MHz devices is benign — the decoder
* only reads the first 24 symbols regardless of total length. */
.signal_range_min_ns = 3000,
.signal_range_max_ns = 1250000,
};
@@ -71,7 +75,7 @@ static void rf_433_receiver_task(void* param) {
.gpio_num = (gpio_num_t)RF_PIN,
.clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = 1000000,
.mem_block_symbols = 64,
.mem_block_symbols = 64, /* ESP32 non-DMA RMT: 1 block = 64 symbols max */
.flags = {
.invert_in = false,
.with_dma = false,

View File

@@ -84,7 +84,8 @@ void soft_idle_enter(void)
i2c_set_led1(0);
}
bool soft_idle_is_active(void) { return in_soft_idle; }
bool soft_idle_is_active(void) { return in_soft_idle; }
bool soft_idle_button_raw(void) { return gpio_get_level(PIN_BTN_INTERRUPT) == 0; }
void soft_idle_exit(void)
{

View File

@@ -35,6 +35,7 @@ void rtc_reset_shutdown_timer(); // reset shutoff timer
void soft_idle_enter(void);
void soft_idle_exit(void);
bool soft_idle_is_active(void);
bool soft_idle_button_raw(void); /* direct GPIO read, no I2C */
esp_sleep_wakeup_cause_t rtc_wakeup_cause();
/*void adjust_rtc_hour(char *key, int8_t dir);

View File

@@ -9,6 +9,7 @@
#include "storage.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "nvs_flash.h"
#include "version.h"
#define TAG "STORAGE"
@@ -424,7 +425,17 @@ esp_err_t factory_reset(void) {
esp_err_t storage_init(void) {
ESP_LOGI(TAG, "Initializing storage system...");
// NVS must be initialized before WiFi and BT
esp_err_t nvs_err = nvs_flash_init();
if (nvs_err == ESP_ERR_NVS_NO_FREE_PAGES || nvs_err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_LOGW(TAG, "NVS partition needs erasing, performing erase...");
nvs_err = nvs_flash_erase();
if (nvs_err == ESP_OK) nvs_err = nvs_flash_init();
}
if (nvs_err != ESP_OK) {
ESP_LOGE(TAG, "nvs_flash_init failed: %s", esp_err_to_name(nvs_err));
return nvs_err;
}
log_mutex = xSemaphoreCreateMutex();
if (log_mutex == NULL) {

View File

@@ -432,6 +432,9 @@ static esp_err_t get_handler(httpd_req_t *req) {
* }
* }
*/
static void soft_idle_enter_cb(void *arg) { soft_idle_enter(); }
static void webserver_restart_wifi_cb(void *arg) { webserver_restart_wifi(); }
/**
* Unified POST handler - handles commands, parameter updates, time updates
*/
@@ -523,15 +526,39 @@ static esp_err_t post_handler(httpd_req_t *req) {
}
if (should_restart_wifi) {
vTaskDelay(pdMS_TO_TICKS(500)); // Let the TCP response flush
webserver_restart_wifi();
/* Same deadlock risk as should_sleep — httpd_stop() inside
* webserver_restart_wifi() cannot be called from within a handler. */
static esp_timer_handle_t s_wifi_restart_timer = NULL;
if (s_wifi_restart_timer == NULL) {
esp_timer_create_args_t ta = {
.callback = webserver_restart_wifi_cb,
.name = "wifi_restart",
};
esp_timer_create(&ta, &s_wifi_restart_timer);
}
if (s_wifi_restart_timer != NULL) {
esp_timer_start_once(s_wifi_restart_timer, 500 * 1000); /* 500 ms in µs */
}
return ESP_OK;
}
if (should_sleep) {
ESP_LOGI(TAG, "Entering soft idle in 2 seconds...");
vTaskDelay(pdMS_TO_TICKS(2000));
soft_idle_enter();
/* Cannot call soft_idle_enter() (→ httpd_stop()) from within an httpd
* handler — httpd_stop() waits for all handlers to finish, causing a
* deadlock. Schedule via a one-shot timer so this handler returns
* first and the httpd task is free. */
static esp_timer_handle_t s_sleep_timer = NULL;
if (s_sleep_timer == NULL) {
esp_timer_create_args_t ta = {
.callback = soft_idle_enter_cb,
.name = "soft_idle",
};
esp_timer_create(&ta, &s_sleep_timer);
}
if (s_sleep_timer != NULL) {
esp_timer_start_once(s_sleep_timer, 2000 * 1000); /* 2 s in µs */
}
return ESP_OK;
}
@@ -881,29 +908,8 @@ static esp_err_t launch_soft_ap(void) {
ESP_LOGI(TAG, "AP LAUNCHING");
err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
// NVS partition was truncated and needs to be erased
ESP_LOGW(TAG, "NVS partition needs erasing, performing erase...");
err = nvs_flash_erase();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to erase NVS: %s", esp_err_to_name(err));
return err;
}
// Retry init after erase
err = nvs_flash_init();
}
ESP_LOGI(TAG, "AP LAUNCHING...");
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize NVS: %s", esp_err_to_name(err));
return err;
}
ESP_LOGI(TAG, "HI THERE");
err = esp_netif_init();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize netif: %s", esp_err_to_name(err));