Persist accelerometer deadzone in NVS across reboots.
Each node saves its local deadzone on UART or ESP-NOW set; pod_settings loads and applies it after BMA456 init. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
2e88358c53
commit
5c3cf65bca
@ -30,6 +30,7 @@ idf_component_register(
|
|||||||
"esp_now_proto.c"
|
"esp_now_proto.c"
|
||||||
"bosch456.c"
|
"bosch456.c"
|
||||||
"board_input.c"
|
"board_input.c"
|
||||||
|
"pod_settings.c"
|
||||||
"proto/uart_messages.pb.c"
|
"proto/uart_messages.pb.c"
|
||||||
"proto/esp_now_messages.pb.c"
|
"proto/esp_now_messages.pb.c"
|
||||||
"proto/pb_encode.c"
|
"proto/pb_encode.c"
|
||||||
|
|||||||
@ -82,12 +82,14 @@ Powerpod uses the Bosch **BMA456H** (hearable) variant, not the generic `bma456w
|
|||||||
|
|
||||||
**Accel logging:** Samples are printed only when any axis changes by more than the **deadzone** (raw LSB) since the last logged sample (default **100**). This is a **software** filter on top of the sensor; it does not change BMA456 hardware thresholds.
|
**Accel logging:** Samples are printed only when any axis changes by more than the **deadzone** (raw LSB) since the last logged sample (default **100**). This is a **software** filter on top of the sensor; it does not change BMA456 hardware thresholds.
|
||||||
|
|
||||||
|
**Persistence:** The local deadzone is stored in the **`nvs`** partition (namespace `powerpod`, key `accel_dz`) via `pod_settings.c`. Each node (master or slave) keeps its own value across reboot. Loaded at boot after `init_bma456()`; saved when set locally (UART `client_id = 0`, `all_clients` on master, or ESP-NOW deadzone on a slave).
|
||||||
|
|
||||||
**Configuration paths:**
|
**Configuration paths:**
|
||||||
|
|
||||||
| Path | Effect |
|
| Path | Effect |
|
||||||
|------|--------|
|
|------|--------|
|
||||||
| UART `ACCEL_DEADZONE` with `client_id = 0` | `bma456_set_accel_deadzone()` on the local node |
|
| UART `ACCEL_DEADZONE` with `client_id = 0` | Set + save local deadzone |
|
||||||
| ESP-NOW `SET_ACCEL_DEADZONE` | Same on a slave (no-op log path if sensor not installed) |
|
| ESP-NOW `SET_ACCEL_DEADZONE` | Set + save on the receiving slave |
|
||||||
| `make gotool-deadzone-set DEADZONE=… CLIENT=0` | Host shortcut for local deadzone |
|
| `make gotool-deadzone-set DEADZONE=… CLIENT=0` | Host shortcut for local deadzone |
|
||||||
|
|
||||||
**Logs:** `[BMA456] ACC X=… Y=… Z=…` when deadzone exceeded; `[BMA456] tap: single|double|triple` on interrupt.
|
**Logs:** `[BMA456] ACC X=… Y=… Z=…` when deadzone exceeded; `[BMA456] tap: single|double|triple` on interrupt.
|
||||||
@ -440,6 +442,7 @@ Target: ESP32-S3. Close serial monitor on the UART adapter port before running `
|
|||||||
| `client_registry.c/h` | Registered slave table |
|
| `client_registry.c/h` | Registered slave table |
|
||||||
| `bosch456.c/h` | BMA456H I2C driver, accel poll, tap INT, deadzone filter |
|
| `bosch456.c/h` | BMA456H I2C driver, accel poll, tap INT, deadzone filter |
|
||||||
| `board_input.c/h` | Taster GPIO12, LiPo ADC on GPIO1 / GPIO12 |
|
| `board_input.c/h` | Taster GPIO12, LiPo ADC on GPIO1 / GPIO12 |
|
||||||
|
| `pod_settings.c/h` | NVS persistence (accel deadzone, …) |
|
||||||
| `led_ring.c/h` | LED ring (digit display, progress bar) |
|
| `led_ring.c/h` | LED ring (digit display, progress bar) |
|
||||||
| `cmd_led_ring.c` | UART `LED_RING` progress command |
|
| `cmd_led_ring.c` | UART `LED_RING` progress command |
|
||||||
| `proto/uart_messages.proto` | UART protocol schema |
|
| `proto/uart_messages.proto` | UART protocol schema |
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#include "cmd_accel_deadzone.h"
|
#include "cmd_accel_deadzone.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "esp_now_comm.h"
|
#include "esp_now_comm.h"
|
||||||
|
#include "pod_settings.h"
|
||||||
#include "uart_cmd.h"
|
#include "uart_cmd.h"
|
||||||
|
|
||||||
static const char *TAG = "[ACCEL_DZ]";
|
static const char *TAG = "[ACCEL_DZ]";
|
||||||
@ -19,6 +20,14 @@ static void reply(uint32_t deadzone, uint32_t client_id, bool success,
|
|||||||
uart_cmd_send(&response, TAG);
|
uart_cmd_send(&response, TAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void apply_local_deadzone(uint32_t deadzone) {
|
||||||
|
bma456_set_accel_deadzone(deadzone);
|
||||||
|
if (pod_settings_save_accel_deadzone(deadzone) != ESP_OK) {
|
||||||
|
ESP_LOGW(TAG, "deadzone %lu applied but not saved to NVS",
|
||||||
|
(unsigned long)deadzone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static esp_err_t push_deadzone_to_slave(const client_info_t *client,
|
static esp_err_t push_deadzone_to_slave(const client_info_t *client,
|
||||||
uint32_t deadzone) {
|
uint32_t deadzone) {
|
||||||
if (client == NULL) {
|
if (client == NULL) {
|
||||||
@ -67,7 +76,7 @@ static void handle_accel_deadzone(const uint8_t *data, size_t len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (bma456_is_ready()) {
|
if (bma456_is_ready()) {
|
||||||
bma456_set_accel_deadzone(req.deadzone);
|
apply_local_deadzone(req.deadzone);
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "set deadzone %lu via unicast to %u/%u slaves",
|
ESP_LOGI(TAG, "set deadzone %lu via unicast to %u/%u slaves",
|
||||||
@ -77,7 +86,7 @@ static void handle_accel_deadzone(const uint8_t *data, size_t len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (req.client_id == 0) {
|
if (req.client_id == 0) {
|
||||||
bma456_set_accel_deadzone(req.deadzone);
|
apply_local_deadzone(req.deadzone);
|
||||||
ESP_LOGI(TAG, "set local deadzone %lu (no ESP-NOW; use -client or -all "
|
ESP_LOGI(TAG, "set local deadzone %lu (no ESP-NOW; use -client or -all "
|
||||||
"for slaves)",
|
"for slaves)",
|
||||||
(unsigned long)req.deadzone);
|
(unsigned long)req.deadzone);
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#include "esp_now_comm.h"
|
#include "esp_now_comm.h"
|
||||||
#include "led_ring.h"
|
#include "led_ring.h"
|
||||||
#include "ota_espnow.h"
|
#include "ota_espnow.h"
|
||||||
|
#include "pod_settings.h"
|
||||||
#include "esp_now_proto.h"
|
#include "esp_now_proto.h"
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "esp_event.h"
|
#include "esp_event.h"
|
||||||
@ -13,7 +14,6 @@
|
|||||||
#include "esp_wifi.h"
|
#include "esp_wifi.h"
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/idf_additions.h"
|
#include "freertos/idf_additions.h"
|
||||||
#include "nvs_flash.h"
|
|
||||||
#include "ota_uart.h"
|
#include "ota_uart.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -399,6 +399,10 @@ static void handle_slave_accel_deadzone(const uint8_t *master_mac,
|
|||||||
bma456_is_ready() ? "ok" : "not installed");
|
bma456_is_ready() ? "ok" : "not installed");
|
||||||
|
|
||||||
bma456_set_accel_deadzone(cfg->deadzone);
|
bma456_set_accel_deadzone(cfg->deadzone);
|
||||||
|
if (pod_settings_save_accel_deadzone(cfg->deadzone) != ESP_OK) {
|
||||||
|
ESP_LOGW(TAG, "slave deadzone %lu applied but not saved to NVS",
|
||||||
|
(unsigned long)cfg->deadzone);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_client_presence(const alox_EspNowSlavePresence *presence,
|
static void handle_client_presence(const alox_EspNowSlavePresence *presence,
|
||||||
@ -607,17 +611,6 @@ static void master_discover_task(void *param) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static esp_err_t init_wifi_stack(uint8_t channel) {
|
static esp_err_t init_wifi_stack(uint8_t channel) {
|
||||||
esp_err_t err;
|
|
||||||
|
|
||||||
err = nvs_flash_init();
|
|
||||||
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
|
||||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
|
||||||
err = nvs_flash_init();
|
|
||||||
}
|
|
||||||
if (err != ESP_OK) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
ESP_ERROR_CHECK(esp_netif_init());
|
ESP_ERROR_CHECK(esp_netif_init());
|
||||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||||
|
|
||||||
|
|||||||
110
main/pod_settings.c
Normal file
110
main/pod_settings.c
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
#include "pod_settings.h"
|
||||||
|
#include "bosch456.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "nvs.h"
|
||||||
|
#include "nvs_flash.h"
|
||||||
|
|
||||||
|
static const char *TAG = "[SETTINGS]";
|
||||||
|
static const char *NS = "powerpod";
|
||||||
|
static const char *KEY_ACCEL_DZ = "accel_dz";
|
||||||
|
|
||||||
|
#define ACCEL_DEADZONE_MAX 4095u
|
||||||
|
|
||||||
|
static bool s_nvs_ready;
|
||||||
|
|
||||||
|
static esp_err_t ensure_nvs(void) {
|
||||||
|
if (s_nvs_ready) {
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
return pod_settings_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t pod_settings_init(void) {
|
||||||
|
if (s_nvs_ready) {
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t err = nvs_flash_init();
|
||||||
|
if (err == ESP_ERR_NVS_NO_FREE_PAGES ||
|
||||||
|
err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||||
|
ESP_LOGW(TAG, "NVS erase and re-init");
|
||||||
|
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||||
|
err = nvs_flash_init();
|
||||||
|
}
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "nvs_flash_init failed: %s", esp_err_to_name(err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_nvs_ready = true;
|
||||||
|
ESP_LOGI(TAG, "NVS ready, accel deadzone %lu LSB (stored)",
|
||||||
|
(unsigned long)pod_settings_load_accel_deadzone());
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t pod_settings_load_accel_deadzone(void) {
|
||||||
|
if (!s_nvs_ready) {
|
||||||
|
return BMA456_DEFAULT_ACCEL_DEADZONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
nvs_handle_t handle;
|
||||||
|
esp_err_t err = nvs_open(NS, NVS_READONLY, &handle);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
return BMA456_DEFAULT_ACCEL_DEADZONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t value = BMA456_DEFAULT_ACCEL_DEADZONE;
|
||||||
|
err = nvs_get_u32(handle, KEY_ACCEL_DZ, &value);
|
||||||
|
nvs_close(handle);
|
||||||
|
|
||||||
|
if (err == ESP_ERR_NVS_NOT_FOUND) {
|
||||||
|
return BMA456_DEFAULT_ACCEL_DEADZONE;
|
||||||
|
}
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGW(TAG, "read accel_dz failed: %s", esp_err_to_name(err));
|
||||||
|
return BMA456_DEFAULT_ACCEL_DEADZONE;
|
||||||
|
}
|
||||||
|
if (value > ACCEL_DEADZONE_MAX) {
|
||||||
|
return BMA456_DEFAULT_ACCEL_DEADZONE;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t pod_settings_save_accel_deadzone(uint32_t deadzone_lsb) {
|
||||||
|
if (deadzone_lsb > ACCEL_DEADZONE_MAX) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t err = ensure_nvs();
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
nvs_handle_t handle;
|
||||||
|
err = nvs_open(NS, NVS_READWRITE, &handle);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "nvs_open failed: %s", esp_err_to_name(err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = nvs_set_u32(handle, KEY_ACCEL_DZ, deadzone_lsb);
|
||||||
|
if (err == ESP_OK) {
|
||||||
|
err = nvs_commit(handle);
|
||||||
|
}
|
||||||
|
nvs_close(handle);
|
||||||
|
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "save accel_dz failed: %s", esp_err_to_name(err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "saved accel deadzone %lu LSB", (unsigned long)deadzone_lsb);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pod_settings_apply_accel_deadzone(void) {
|
||||||
|
uint32_t deadzone = pod_settings_load_accel_deadzone();
|
||||||
|
if (bma456_is_ready()) {
|
||||||
|
bma456_set_accel_deadzone(deadzone);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
main/pod_settings.h
Normal file
19
main/pod_settings.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef POD_SETTINGS_H
|
||||||
|
#define POD_SETTINGS_H
|
||||||
|
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/** Initialize NVS (idempotent) and log stored settings. Call once early in app_main. */
|
||||||
|
esp_err_t pod_settings_init(void);
|
||||||
|
|
||||||
|
/** Persist local accelerometer deadzone (LSB per axis). */
|
||||||
|
esp_err_t pod_settings_save_accel_deadzone(uint32_t deadzone_lsb);
|
||||||
|
|
||||||
|
/** Load deadzone from NVS, or BMA456_DEFAULT_ACCEL_DEADZONE if unset. */
|
||||||
|
uint32_t pod_settings_load_accel_deadzone(void);
|
||||||
|
|
||||||
|
/** Apply NVS deadzone to BMA456 when the sensor is present. */
|
||||||
|
void pod_settings_apply_accel_deadzone(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -22,6 +22,7 @@
|
|||||||
#include "board_input.h"
|
#include "board_input.h"
|
||||||
#include "bosch456.h"
|
#include "bosch456.h"
|
||||||
#include "led_ring.h"
|
#include "led_ring.h"
|
||||||
|
#include "pod_settings.h"
|
||||||
#include "uart.h"
|
#include "uart.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
@ -66,6 +67,10 @@ uint8_t reverse_high_nibble_lut(uint8_t n) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void app_main(void) {
|
void app_main(void) {
|
||||||
|
if (pod_settings_init() != ESP_OK) {
|
||||||
|
ESP_LOGW(TAG, "settings NVS init failed; using defaults");
|
||||||
|
}
|
||||||
|
|
||||||
// Get Master Mode Pin
|
// Get Master Mode Pin
|
||||||
gpio_reset_pin(DIP_MASTER);
|
gpio_reset_pin(DIP_MASTER);
|
||||||
gpio_set_direction(DIP_MASTER, GPIO_MODE_INPUT);
|
gpio_set_direction(DIP_MASTER, GPIO_MODE_INPUT);
|
||||||
@ -125,6 +130,8 @@ void app_main(void) {
|
|||||||
esp_err_t bma_err = init_bma456(bus_handle);
|
esp_err_t bma_err = init_bma456(bus_handle);
|
||||||
if (bma_err != ESP_OK) {
|
if (bma_err != ESP_OK) {
|
||||||
ESP_LOGI(TAG, "BMA456 init skipped: %s", esp_err_to_name(bma_err));
|
ESP_LOGI(TAG, "BMA456 init skipped: %s", esp_err_to_name(bma_err));
|
||||||
|
} else {
|
||||||
|
pod_settings_apply_accel_deadzone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user