Add runtime UV protection toggle and treat near-zero sense as external power.
Per-pod NVS enable (default off) via UART/ESP-NOW/dashboard, and skip UV latch when LiPo ADC reads ~0 mV so USB/external supply still boots. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -34,6 +34,7 @@ idf_component_register(
|
||||
"pod_reboot.c"
|
||||
"cmd/cmd_led_ring.c"
|
||||
"cmd/cmd_battery.c"
|
||||
"cmd/cmd_battery_uv.c"
|
||||
"cmd/cmd_set_log_level.c"
|
||||
"cmd/cmd_ota.c"
|
||||
"cmd/cmd_ota_slave_progress.c"
|
||||
|
||||
+10
-4
@@ -121,6 +121,7 @@ Schema: `proto/esp_now_messages.proto`. Encode/decode: `esp_now_proto.c`. The ES
|
||||
| `ESPNOW_HEARTBEAT` | Slave → master | `EspNowSlavePresence` (same fields) |
|
||||
| `ESPNOW_SET_ACCEL_DEADZONE` | Master → slave | `EspNowAccelDeadzone` (`deadzone` LSB) |
|
||||
| `ESPNOW_SET_TAP_CONFIG` | Master → slave | `EspNowTapConfig` (multitap sens/timing/axis + enable S/D/T) |
|
||||
| `ESPNOW_SET_BATTERY_UV` | Master → slave | `EspNowBatteryUv` (runtime UV enable + clear latch when off) |
|
||||
| `ESPNOW_UNICAST_TEST` | Master → slave | `EspNowUnicastTest` (`seq`) |
|
||||
| `ESPNOW_FIND_ME` | Master → slave | `EspNowFindMe` (`client_id` filter) — LED locate sequence |
|
||||
| `ESPNOW_RESTART` | Master → slave | `EspNowRestart` (`client_id` filter) — reboot slave |
|
||||
@@ -240,6 +241,7 @@ Host and master speak nanopb-encoded `UartMessage` inside UART frames (byte 0 =
|
||||
| 30 | `ESPNOW_ECHO_PING` | Implemented (`cmd/cmd_espnow_echo_ping.c`) — ESP-NOW timestamp echo (latency test) |
|
||||
| 31 | `SET_LOG_LEVEL` | Implemented (`cmd/cmd_set_log_level.c`) — get/set global `esp_log_level_set("*", …)` on master |
|
||||
| 32 | `TAP_CONFIG` | Implemented (`cmd/cmd_tap_config.c`) — get/set BMA456H multitap params (+ NVS) |
|
||||
| 36 | `BATTERY_UV` | Implemented (`cmd/cmd_battery_uv.c`) — get/set software UV enable (+ NVS / ESP-NOW) |
|
||||
|
||||
Regenerate C code:
|
||||
|
||||
@@ -473,14 +475,17 @@ Read **cached** LiPo ADC values on the **master** (master local + one entry per
|
||||
|
||||
### Software UV protection (LiPo)
|
||||
|
||||
When `POWERPOD_BATTERY_UV_ENABLE` is `1` (default in `powerpod.h`, disable via CMake), the firmware monitors ADC pin voltages on GPIO 1 and 11:
|
||||
When `POWERPOD_BATTERY_UV_ENABLE` is `1` (default in `powerpod.h`, disable via CMake), the firmware can monitor ADC pin voltages on GPIO 1 and 11. Runtime enable is NVS `uv_en` per pod (missing key → **disabled**); UART `BATTERY_UV` / dashboard toggles it on master and slaves.
|
||||
|
||||
| Condition | ADC threshold | Action |
|
||||
|-----------|---------------|--------|
|
||||
| Under-voltage | any valid channel < **2300 mV** (3.0 V pack) | NVS latch `uv_latch`, restart into energy-save mode |
|
||||
| Charged | all valid channels ≥ **3000 mV** (4.0 V pack) | Clear latch, restart into normal boot |
|
||||
| External / absent | every valid channel < **100 mV** | Normal boot (no UV); clears latch if set |
|
||||
| Under-voltage | any valid channel in **100…2299 mV** | NVS latch `uv_latch`, restart into energy-save mode |
|
||||
| Charged | every non-absent valid channel ≥ **3000 mV** | Clear latch, restart into normal boot |
|
||||
|
||||
**Energy-save boot:** LED mode `6` (first 4 LEDs red ~10 % for 5 s), then no WiFi/ESP-NOW, UART, I2C, BMA456, or button — only LiPo ADC polling every 30 s until charged.
|
||||
**Energy-save boot:** LED mode `6` (first 4 LEDs red ~10 % for 5 s), then no WiFi/ESP-NOW, UART, I2C, BMA456, or button — only LiPo ADC polling every 30 s until charged. Disabling UV while latched clears the latch (requires a reachable host — not while already in energy-save).
|
||||
|
||||
**UART:** `BATTERY_UV` (`0x24`) — `client_id=0` master, `>0` one slave, `all_clients` master + all slaves. Disabling also clears `uv_latch`.
|
||||
|
||||
**Test LED pattern from host:** `led-ring -mode battery-low` (works even when UV feature is disabled).
|
||||
|
||||
@@ -614,6 +619,7 @@ Target: ESP32-S3. Close serial monitor on the UART adapter port before running `
|
||||
| `pod_settings.c/h` | NVS persistence (accel deadzone, tap config, UV latch) |
|
||||
| `led_ring.c/h` | LED ring (digit display, progress bar) |
|
||||
| `cmd/cmd_led_ring.c` | UART `LED_RING` progress command |
|
||||
| `cmd/cmd_battery_uv.c` | UART `BATTERY_UV` — software UV enable + NVS / ESP-NOW |
|
||||
| `cmd/cmd_set_log_level.c` | UART `SET_LOG_LEVEL` — runtime ESP-IDF log level |
|
||||
| `proto/uart_messages.proto` | UART protocol schema |
|
||||
| `proto/esp_now_messages.proto` | ESP-NOW protocol schema |
|
||||
|
||||
+76
-10
@@ -19,15 +19,55 @@ static uint8_t s_charge_streak;
|
||||
|
||||
bool battery_uv_is_latched(void) { return pod_settings_is_uv_latched(); }
|
||||
|
||||
static bool channel_is_absent(uint32_t mv) {
|
||||
return mv < BATTERY_UV_ABSENT_ADC_MV;
|
||||
}
|
||||
|
||||
static bool channel_is_under(uint32_t mv) {
|
||||
return !channel_is_absent(mv) && mv < BATTERY_UV_ADC_MV;
|
||||
}
|
||||
|
||||
static void log_lipo_reading(const char *ctx, const board_lipo_reading_t *reading) {
|
||||
if (reading == NULL) {
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG,
|
||||
"%s LIPO1 %s %lu mV LIPO2 %s %lu mV", ctx,
|
||||
reading->lipo1_valid ? "ok" : "n/a",
|
||||
(unsigned long)reading->lipo1_mv, reading->lipo2_valid ? "ok" : "n/a",
|
||||
(unsigned long)reading->lipo2_mv);
|
||||
}
|
||||
|
||||
bool battery_uv_reading_is_external(const board_lipo_reading_t *reading) {
|
||||
if (reading == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool any_valid = false;
|
||||
if (reading->lipo1_valid) {
|
||||
any_valid = true;
|
||||
if (!channel_is_absent(reading->lipo1_mv)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (reading->lipo2_valid) {
|
||||
any_valid = true;
|
||||
if (!channel_is_absent(reading->lipo2_mv)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return any_valid;
|
||||
}
|
||||
|
||||
bool battery_uv_reading_is_under(const board_lipo_reading_t *reading) {
|
||||
if (reading == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (reading->lipo1_valid && reading->lipo1_mv < BATTERY_UV_ADC_MV) {
|
||||
if (reading->lipo1_valid && channel_is_under(reading->lipo1_mv)) {
|
||||
return true;
|
||||
}
|
||||
if (reading->lipo2_valid && reading->lipo2_mv < BATTERY_UV_ADC_MV) {
|
||||
if (reading->lipo2_valid && channel_is_under(reading->lipo2_mv)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -38,25 +78,39 @@ bool battery_uv_reading_is_charged(const board_lipo_reading_t *reading) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool any_valid = false;
|
||||
if (reading->lipo1_valid) {
|
||||
any_valid = true;
|
||||
bool any_pack = false;
|
||||
if (reading->lipo1_valid && !channel_is_absent(reading->lipo1_mv)) {
|
||||
any_pack = true;
|
||||
if (reading->lipo1_mv < BATTERY_CHARGE_ADC_MV) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (reading->lipo2_valid) {
|
||||
any_valid = true;
|
||||
if (reading->lipo2_valid && !channel_is_absent(reading->lipo2_mv)) {
|
||||
any_pack = true;
|
||||
if (reading->lipo2_mv < BATTERY_CHARGE_ADC_MV) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return any_valid;
|
||||
return any_pack;
|
||||
}
|
||||
|
||||
bool battery_uv_evaluate_boot(void) {
|
||||
if (!pod_settings_is_uv_enabled()) {
|
||||
ESP_LOGI(TAG, "UV protection disabled — normal boot");
|
||||
return false;
|
||||
}
|
||||
|
||||
board_lipo_reading_t reading;
|
||||
board_input_read_lipo(&reading);
|
||||
log_lipo_reading("boot check", &reading);
|
||||
|
||||
if (battery_uv_reading_is_external(&reading)) {
|
||||
ESP_LOGI(TAG, "near-zero LiPo sense — external supply, normal boot");
|
||||
if (pod_settings_is_uv_latched()) {
|
||||
pod_settings_clear_uv_latched();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pod_settings_is_uv_latched() && battery_uv_reading_is_charged(&reading)) {
|
||||
ESP_LOGI(TAG, "charged — clearing UV latch");
|
||||
@@ -78,12 +132,19 @@ bool battery_uv_evaluate_boot(void) {
|
||||
}
|
||||
|
||||
void battery_uv_poll(const board_lipo_reading_t *reading) {
|
||||
if (reading == NULL || pod_settings_is_uv_latched()) {
|
||||
if (reading == NULL || !pod_settings_is_uv_enabled() ||
|
||||
pod_settings_is_uv_latched()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (battery_uv_reading_is_external(reading)) {
|
||||
s_uv_streak = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (battery_uv_reading_is_under(reading)) {
|
||||
s_uv_streak++;
|
||||
log_lipo_reading("under-voltage", reading);
|
||||
ESP_LOGW(TAG, "under-voltage sample %u/%u", (unsigned)s_uv_streak,
|
||||
(unsigned)UV_DEBOUNCE_SAMPLES);
|
||||
if (s_uv_streak >= UV_DEBOUNCE_SAMPLES) {
|
||||
@@ -109,8 +170,13 @@ void battery_uv_run_mode(void) {
|
||||
while (1) {
|
||||
board_lipo_reading_t reading;
|
||||
board_input_read_lipo(&reading);
|
||||
log_lipo_reading("energy-save", &reading);
|
||||
|
||||
if (battery_uv_reading_is_charged(&reading)) {
|
||||
if (battery_uv_reading_is_external(&reading)) {
|
||||
ESP_LOGI(TAG, "external supply — clearing UV latch and restarting");
|
||||
pod_settings_clear_uv_latched();
|
||||
pod_schedule_restart();
|
||||
} else if (battery_uv_reading_is_charged(&reading)) {
|
||||
s_charge_streak++;
|
||||
ESP_LOGI(TAG, "charge sample %u/%u", (unsigned)s_charge_streak,
|
||||
(unsigned)UV_DEBOUNCE_SAMPLES);
|
||||
|
||||
@@ -11,10 +11,17 @@
|
||||
#define BATTERY_UV_ADC_MV 2300u
|
||||
/** ADC pin voltage (mV) at which charging is detected (4.0 V pack, rounded). */
|
||||
#define BATTERY_CHARGE_ADC_MV 3000u
|
||||
/**
|
||||
* ADC readings below this are treated as no pack / external supply (not UV).
|
||||
* Noise floor / open sense divider → near 0 mV.
|
||||
*/
|
||||
#define BATTERY_UV_ABSENT_ADC_MV 100u
|
||||
|
||||
bool battery_uv_is_latched(void);
|
||||
bool battery_uv_reading_is_under(const board_lipo_reading_t *reading);
|
||||
bool battery_uv_reading_is_charged(const board_lipo_reading_t *reading);
|
||||
/** true when every valid channel is near 0 (externally powered / no LiPo). */
|
||||
bool battery_uv_reading_is_external(const board_lipo_reading_t *reading);
|
||||
|
||||
/** true → enter UV energy-save path (does not return). */
|
||||
bool battery_uv_evaluate_boot(void);
|
||||
@@ -38,6 +45,11 @@ static inline bool battery_uv_reading_is_charged(const board_lipo_reading_t *rea
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool battery_uv_reading_is_external(const board_lipo_reading_t *reading) {
|
||||
(void)reading;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool battery_uv_evaluate_boot(void) { return false; }
|
||||
|
||||
static inline void battery_uv_poll(const board_lipo_reading_t *reading) {
|
||||
|
||||
@@ -143,6 +143,7 @@ static client_slot_t *alloc_slot(const uint8_t mac[CLIENT_MAC_LEN],
|
||||
static const bma456_tap_config_t k_tap_default = BMA456_TAP_CONFIG_DEFAULT;
|
||||
slot->info.tap_config = k_tap_default;
|
||||
}
|
||||
slot->info.uv_protection_enabled = false;
|
||||
if (out_is_new != NULL) {
|
||||
*out_is_new = true;
|
||||
}
|
||||
@@ -435,6 +436,41 @@ size_t client_registry_set_tap_config_all(const bma456_tap_config_t *cfg) {
|
||||
return n;
|
||||
}
|
||||
|
||||
esp_err_t client_registry_set_uv_protection(uint32_t client_id, bool enabled) {
|
||||
for (size_t i = 0; i < CLIENT_REGISTRY_MAX; i++) {
|
||||
if (s_clients[i].active && s_clients[i].info.id == client_id) {
|
||||
s_clients[i].info.uv_protection_enabled = enabled;
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
esp_err_t client_registry_get_uv_protection(uint32_t client_id,
|
||||
bool *enabled_out) {
|
||||
if (enabled_out == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
const client_info_t *info = client_registry_find_by_id(client_id);
|
||||
if (info == NULL) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
*enabled_out = info->uv_protection_enabled;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
size_t client_registry_set_uv_protection_all(bool enabled) {
|
||||
size_t n = 0;
|
||||
for (size_t i = 0; i < CLIENT_REGISTRY_MAX; i++) {
|
||||
if (!s_clients[i].active) {
|
||||
continue;
|
||||
}
|
||||
s_clients[i].info.uv_protection_enabled = enabled;
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static void clear_client_accel(client_slot_t *slot) {
|
||||
if (slot == NULL) {
|
||||
return;
|
||||
|
||||
@@ -47,6 +47,8 @@ typedef struct {
|
||||
uint32_t lipo1_mv;
|
||||
uint32_t lipo2_mv;
|
||||
uint32_t battery_updated_at;
|
||||
/** Master cache: software UV protection enabled on slave (default false). */
|
||||
bool uv_protection_enabled;
|
||||
/** Master: last ESPNOW_ASSIGN_ID send time (rate-limit resends). */
|
||||
uint32_t last_assign_sent_at;
|
||||
} client_info_t;
|
||||
@@ -119,6 +121,11 @@ esp_err_t client_registry_get_tap_config(uint32_t client_id,
|
||||
bma456_tap_config_t *cfg_out);
|
||||
size_t client_registry_set_tap_config_all(const bma456_tap_config_t *cfg);
|
||||
|
||||
esp_err_t client_registry_set_uv_protection(uint32_t client_id, bool enabled);
|
||||
esp_err_t client_registry_get_uv_protection(uint32_t client_id,
|
||||
bool *enabled_out);
|
||||
size_t client_registry_set_uv_protection_all(bool enabled);
|
||||
|
||||
/** Store latest accel sample from a slave (matched by sender MAC). */
|
||||
esp_err_t client_registry_update_accel(const uint8_t mac[CLIENT_MAC_LEN],
|
||||
uint32_t slave_id, int16_t x, int16_t y,
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
#include "cmd_battery_uv.h"
|
||||
#include "client_registry.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_now_comm.h"
|
||||
#include "pod_settings.h"
|
||||
#include "uart_cmd.h"
|
||||
|
||||
static const char *TAG = "[BATTERY_UV_CMD]";
|
||||
|
||||
static void reply(uint32_t client_id, bool success, bool enabled, bool latched,
|
||||
uint32_t slaves_updated) {
|
||||
alox_UartMessage response;
|
||||
uart_cmd_init_response(&response, alox_MessageType_BATTERY_UV,
|
||||
alox_UartMessage_battery_uv_response_tag);
|
||||
response.payload.battery_uv_response.client_id = client_id;
|
||||
response.payload.battery_uv_response.success = success;
|
||||
response.payload.battery_uv_response.enabled = enabled;
|
||||
response.payload.battery_uv_response.latched = latched;
|
||||
response.payload.battery_uv_response.slaves_updated = slaves_updated;
|
||||
uart_cmd_send(&response, TAG);
|
||||
}
|
||||
|
||||
static esp_err_t apply_local_uv(bool enabled) {
|
||||
esp_err_t err = pod_settings_set_uv_enabled(enabled);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
if (!enabled) {
|
||||
(void)pod_settings_clear_uv_latched();
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t push_uv_to_slave(const client_info_t *client, bool enabled) {
|
||||
if (client == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
esp_err_t err = client_registry_set_uv_protection(client->id, enabled);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
return esp_now_comm_send_battery_uv(client->mac, client->id, enabled);
|
||||
}
|
||||
|
||||
static void handle_battery_uv(const uint8_t *data, size_t len) {
|
||||
alox_UartMessage uart_msg;
|
||||
alox_BatteryUvRequest req = alox_BatteryUvRequest_init_zero;
|
||||
|
||||
if (uart_cmd_decode(data, len, &uart_msg) != ESP_OK) {
|
||||
ESP_LOGW(TAG, "decode failed");
|
||||
reply(0, false, pod_settings_is_uv_enabled(), pod_settings_is_uv_latched(),
|
||||
0);
|
||||
return;
|
||||
}
|
||||
|
||||
const alox_BatteryUvRequest *req_ptr = UART_CMD_REQ(
|
||||
&uart_msg, alox_UartMessage_battery_uv_request_tag, battery_uv_request);
|
||||
if (req_ptr != NULL) {
|
||||
req = *req_ptr;
|
||||
}
|
||||
|
||||
if (req.write) {
|
||||
if (req.all_clients) {
|
||||
(void)client_registry_set_uv_protection_all(req.enabled);
|
||||
uint32_t sent = 0;
|
||||
for (size_t i = 0; i < client_registry_count(); i++) {
|
||||
const client_info_t *client = client_registry_at(i);
|
||||
if (client == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (esp_now_comm_send_battery_uv(client->mac, client->id,
|
||||
req.enabled) == ESP_OK) {
|
||||
sent++;
|
||||
}
|
||||
}
|
||||
|
||||
bool local_ok = apply_local_uv(req.enabled) == ESP_OK;
|
||||
ESP_LOGI(TAG, "UV protection %s local=%d slaves=%u",
|
||||
req.enabled ? "on" : "off", local_ok, (unsigned)sent);
|
||||
reply(0, local_ok || sent > 0, req.enabled,
|
||||
pod_settings_is_uv_latched(), sent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.client_id == 0) {
|
||||
esp_err_t err = apply_local_uv(req.enabled);
|
||||
reply(0, err == ESP_OK, pod_settings_is_uv_enabled(),
|
||||
pod_settings_is_uv_latched(), 0);
|
||||
return;
|
||||
}
|
||||
|
||||
const client_info_t *client = client_registry_find_by_id(req.client_id);
|
||||
if (client == NULL) {
|
||||
ESP_LOGW(TAG, "client id %lu not found", (unsigned long)req.client_id);
|
||||
reply(req.client_id, false, req.enabled, false, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
esp_err_t err = push_uv_to_slave(client, req.enabled);
|
||||
reply(req.client_id, err == ESP_OK, req.enabled, false,
|
||||
err == ESP_OK ? 1 : 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.all_clients || req.client_id == 0) {
|
||||
reply(0, true, pod_settings_is_uv_enabled(), pod_settings_is_uv_latched(),
|
||||
0);
|
||||
return;
|
||||
}
|
||||
|
||||
bool enabled = true;
|
||||
esp_err_t err = client_registry_get_uv_protection(req.client_id, &enabled);
|
||||
reply(req.client_id, err == ESP_OK, enabled, false, 0);
|
||||
}
|
||||
|
||||
void cmd_battery_uv_register(void) {
|
||||
uart_cmd_register(alox_MessageType_BATTERY_UV, handle_battery_uv);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef CMD_BATTERY_UV_H
|
||||
#define CMD_BATTERY_UV_H
|
||||
|
||||
void cmd_battery_uv_register(void);
|
||||
|
||||
#endif
|
||||
@@ -31,6 +31,7 @@ static bool encode_clients_list(pb_ostream_t *stream, const pb_field_t *field,
|
||||
proto.tap_notify_single = client->tap_notify_single;
|
||||
proto.tap_notify_double = client->tap_notify_double;
|
||||
proto.tap_notify_triple = client->tap_notify_triple;
|
||||
proto.uv_protection_enabled = client->uv_protection_enabled;
|
||||
proto.mac.funcs.encode = uart_cmd_encode_bytes;
|
||||
proto.mac.arg = &mac;
|
||||
|
||||
|
||||
@@ -31,6 +31,10 @@ esp_err_t esp_now_comm_send_tap_config(const uint8_t mac[CLIENT_MAC_LEN],
|
||||
uint32_t client_id,
|
||||
const bma456_tap_config_t *cfg);
|
||||
|
||||
/** Master: unicast software UV protection enable to one slave. */
|
||||
esp_err_t esp_now_comm_send_battery_uv(const uint8_t mac[CLIENT_MAC_LEN],
|
||||
uint32_t client_id, bool enabled);
|
||||
|
||||
/** Master: send minimal unicast test payload to verify master→slave path. */
|
||||
esp_err_t esp_now_comm_send_unicast_test(const uint8_t mac[CLIENT_MAC_LEN],
|
||||
uint32_t seq);
|
||||
|
||||
@@ -75,6 +75,16 @@ static esp_err_t send_tap_config(const uint8_t *dest_mac, uint32_t client_id,
|
||||
return esp_now_core_send(dest_mac, &msg);
|
||||
}
|
||||
|
||||
static esp_err_t send_battery_uv(const uint8_t *dest_mac, uint32_t client_id,
|
||||
bool enabled) {
|
||||
alox_EspNowMessage msg = alox_EspNowMessage_init_zero;
|
||||
msg.type = alox_EspNowMessageType_ESPNOW_SET_BATTERY_UV;
|
||||
msg.which_payload = alox_EspNowMessage_battery_uv_tag;
|
||||
msg.payload.battery_uv.client_id = client_id;
|
||||
msg.payload.battery_uv.enabled = enabled;
|
||||
return esp_now_core_send(dest_mac, &msg);
|
||||
}
|
||||
|
||||
static esp_err_t send_unicast_test(const uint8_t *dest_mac, uint32_t seq) {
|
||||
alox_EspNowMessage msg = alox_EspNowMessage_init_zero;
|
||||
msg.type = alox_EspNowMessageType_ESPNOW_UNICAST_TEST;
|
||||
@@ -537,6 +547,24 @@ esp_err_t esp_now_comm_send_tap_config(const uint8_t mac[CLIENT_MAC_LEN],
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_now_comm_send_battery_uv(const uint8_t mac[CLIENT_MAC_LEN],
|
||||
uint32_t client_id, bool enabled) {
|
||||
if (mac == NULL || !esp_now_core_is_master()) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
char mac_str[18];
|
||||
esp_now_core_mac_to_str(mac, mac_str, sizeof(mac_str));
|
||||
esp_err_t err = send_battery_uv(mac, client_id, enabled);
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "unicast SET_BATTERY_UV to %s: enabled=%d client_id=%lu",
|
||||
mac_str, enabled, (unsigned long)client_id);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "unicast SET_BATTERY_UV to %s failed: %s", mac_str,
|
||||
esp_err_to_name(err));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static void handle_accel_sample(const uint8_t mac[CLIENT_MAC_LEN],
|
||||
const alox_EspNowAccelSample *sample) {
|
||||
if (sample == NULL) {
|
||||
|
||||
@@ -640,6 +640,30 @@ static void handle_tap_config(const uint8_t *master_mac,
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_battery_uv(const uint8_t *master_mac,
|
||||
const alox_EspNowBatteryUv *msg) {
|
||||
if (!client_id_matches(msg->client_id)) {
|
||||
return;
|
||||
}
|
||||
if (s_joined && !esp_now_core_mac_equal(master_mac, s_master_mac)) {
|
||||
return;
|
||||
}
|
||||
|
||||
char mac_str[18];
|
||||
esp_now_core_mac_to_str(master_mac, mac_str, sizeof(mac_str));
|
||||
ESP_LOGI(TAG, "UV protection %s from master %s (id=%lu)",
|
||||
msg->enabled ? "enabled" : "disabled", mac_str,
|
||||
(unsigned long)my_client_id());
|
||||
|
||||
if (pod_settings_set_uv_enabled(msg->enabled) != ESP_OK) {
|
||||
ESP_LOGW(TAG, "UV enable save failed");
|
||||
return;
|
||||
}
|
||||
if (!msg->enabled) {
|
||||
(void)pod_settings_clear_uv_latched();
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_assign_id(const uint8_t *master_mac,
|
||||
const alox_EspNowAssignId *msg) {
|
||||
if (!from_joined_master(master_mac)) {
|
||||
@@ -853,6 +877,11 @@ void esp_now_slave_on_recv(const esp_now_recv_info_t *info, const uint8_t *data,
|
||||
handle_tap_config(info->src_addr, &msg.payload.tap_config);
|
||||
}
|
||||
break;
|
||||
case alox_EspNowMessage_battery_uv_tag:
|
||||
if (from_joined_master(info->src_addr)) {
|
||||
handle_battery_uv(info->src_addr, &msg.payload.battery_uv);
|
||||
}
|
||||
break;
|
||||
case alox_EspNowMessage_accel_stream_tag:
|
||||
if (from_joined_master(info->src_addr)) {
|
||||
handle_accel_stream(info->src_addr, &msg.payload.accel_stream);
|
||||
|
||||
@@ -9,6 +9,7 @@ static const char *TAG = "[SETTINGS]";
|
||||
static const char *NS = "powerpod";
|
||||
static const char *KEY_ACCEL_DZ = "accel_dz";
|
||||
static const char *KEY_UV_LATCH = "uv_latch";
|
||||
static const char *KEY_UV_EN = "uv_en";
|
||||
static const char *KEY_TAP_CFG = "tap_cfg";
|
||||
static const char *KEY_ID_MAP = "id_map";
|
||||
static const char *KEY_ID_BIND = "id_bind";
|
||||
@@ -325,6 +326,58 @@ esp_err_t pod_settings_clear_uv_latched(void) {
|
||||
return pod_settings_set_uv_latched(false);
|
||||
}
|
||||
|
||||
bool pod_settings_is_uv_enabled(void) {
|
||||
if (!s_nvs_ready) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nvs_handle_t handle;
|
||||
esp_err_t err = nvs_open(NS, NVS_READONLY, &handle);
|
||||
if (err != ESP_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t value = 0;
|
||||
err = nvs_get_u8(handle, KEY_UV_EN, &value);
|
||||
nvs_close(handle);
|
||||
|
||||
if (err == ESP_ERR_NVS_NOT_FOUND) {
|
||||
return false;
|
||||
}
|
||||
if (err != ESP_OK) {
|
||||
return false;
|
||||
}
|
||||
return value != 0;
|
||||
}
|
||||
|
||||
esp_err_t pod_settings_set_uv_enabled(bool enabled) {
|
||||
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_u8(handle, KEY_UV_EN, enabled ? 1u : 0u);
|
||||
if (err == ESP_OK) {
|
||||
err = nvs_commit(handle);
|
||||
}
|
||||
nvs_close(handle);
|
||||
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "save uv_en failed: %s", esp_err_to_name(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "UV protection %s", enabled ? "enabled" : "disabled");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t pod_settings_load_id_map(pod_id_map_t *out) {
|
||||
if (out == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
|
||||
@@ -35,6 +35,13 @@ bool pod_settings_is_uv_latched(void);
|
||||
esp_err_t pod_settings_set_uv_latched(bool latched);
|
||||
esp_err_t pod_settings_clear_uv_latched(void);
|
||||
|
||||
/**
|
||||
* Runtime enable for software UV protection (NVS). Missing key → disabled.
|
||||
* Independent of POWERPOD_BATTERY_UV_ENABLE compile gate.
|
||||
*/
|
||||
bool pod_settings_is_uv_enabled(void);
|
||||
esp_err_t pod_settings_set_uv_enabled(bool enabled);
|
||||
|
||||
/** Logical slave ids: 1…POD_CLIENT_ID_MAX (0 reserved for local master). */
|
||||
#define POD_CLIENT_ID_MIN 1u
|
||||
#define POD_CLIENT_ID_MAX 255u
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "ota_confirm.h"
|
||||
#include "cmd_led_ring.h"
|
||||
#include "cmd_battery.h"
|
||||
#include "cmd_battery_uv.h"
|
||||
#include "cmd_set_log_level.h"
|
||||
#include "esp_now_comm.h"
|
||||
#include "powerpod.h"
|
||||
@@ -233,6 +234,7 @@ void app_main(void) {
|
||||
cmd_client_id_map_reset_register();
|
||||
cmd_led_ring_register();
|
||||
cmd_battery_register();
|
||||
cmd_battery_uv_register();
|
||||
cmd_ota_register();
|
||||
cmd_ota_slave_progress_register();
|
||||
cmd_set_log_level_register();
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
|
||||
/** 1 = software LiPo UV latch + energy-save mode; 0 = disabled (LED mode 6 still works). */
|
||||
#ifndef POWERPOD_BATTERY_UV_ENABLE
|
||||
#define POWERPOD_BATTERY_UV_ENABLE 0
|
||||
#define POWERPOD_BATTERY_UV_ENABLE 1
|
||||
#endif
|
||||
|
||||
#define DIP_MASTER 4
|
||||
|
||||
@@ -57,6 +57,9 @@ PB_BIND(alox_EspNowTapEvent, alox_EspNowTapEvent, AUTO)
|
||||
PB_BIND(alox_EspNowInputSendMode, alox_EspNowInputSendMode, AUTO)
|
||||
|
||||
|
||||
PB_BIND(alox_EspNowBatteryUv, alox_EspNowBatteryUv, AUTO)
|
||||
|
||||
|
||||
PB_BIND(alox_EspNowBatteryReport, alox_EspNowBatteryReport, AUTO)
|
||||
|
||||
|
||||
|
||||
@@ -38,7 +38,9 @@ typedef enum _alox_EspNowMessageType {
|
||||
/* * Master → slave: forget persisted master/id binding (debug reset). */
|
||||
alox_EspNowMessageType_ESPNOW_CLEAR_ID_BINDING = 23,
|
||||
/* * Master → slave: accel/tap ESP-NOW send path (best_effort/fast/wait/reliable). */
|
||||
alox_EspNowMessageType_ESPNOW_SET_INPUT_SEND_MODE = 24
|
||||
alox_EspNowMessageType_ESPNOW_SET_INPUT_SEND_MODE = 24,
|
||||
/* * Master → slave: enable/disable software LiPo UV protection (NVS). */
|
||||
alox_EspNowMessageType_ESPNOW_SET_BATTERY_UV = 25
|
||||
} alox_EspNowMessageType;
|
||||
|
||||
/* Struct definitions */
|
||||
@@ -161,6 +163,12 @@ typedef struct _alox_EspNowInputSendMode {
|
||||
uint32_t mode;
|
||||
} alox_EspNowInputSendMode;
|
||||
|
||||
/* * Master → slave: software LiPo UV protection enable (persisted in NVS). */
|
||||
typedef struct _alox_EspNowBatteryUv {
|
||||
uint32_t client_id; /* 0 = all slaves; otherwise only matching slave_id applies */
|
||||
bool enabled;
|
||||
} alox_EspNowBatteryUv;
|
||||
|
||||
/* * Slave → master: LiPo voltages (periodic ~30 s and on query). */
|
||||
typedef struct _alox_EspNowBatteryReport {
|
||||
uint32_t client_id;
|
||||
@@ -236,6 +244,7 @@ typedef struct _alox_EspNowMessage {
|
||||
alox_EspNowAssignId assign_id;
|
||||
alox_EspNowClearIdBinding clear_id_binding;
|
||||
alox_EspNowInputSendMode input_send_mode;
|
||||
alox_EspNowBatteryUv battery_uv;
|
||||
} payload;
|
||||
} alox_EspNowMessage;
|
||||
|
||||
@@ -246,8 +255,9 @@ extern "C" {
|
||||
|
||||
/* Helper constants for enums */
|
||||
#define _alox_EspNowMessageType_MIN alox_EspNowMessageType_ESPNOW_UNKNOWN
|
||||
#define _alox_EspNowMessageType_MAX alox_EspNowMessageType_ESPNOW_SET_INPUT_SEND_MODE
|
||||
#define _alox_EspNowMessageType_ARRAYSIZE ((alox_EspNowMessageType)(alox_EspNowMessageType_ESPNOW_SET_INPUT_SEND_MODE+1))
|
||||
#define _alox_EspNowMessageType_MAX alox_EspNowMessageType_ESPNOW_SET_BATTERY_UV
|
||||
#define _alox_EspNowMessageType_ARRAYSIZE ((alox_EspNowMessageType)(alox_EspNowMessageType_ESPNOW_SET_BATTERY_UV+1))
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -293,6 +303,7 @@ extern "C" {
|
||||
#define alox_EspNowTapConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define alox_EspNowTapEvent_init_default {0, 0}
|
||||
#define alox_EspNowInputSendMode_init_default {0, 0}
|
||||
#define alox_EspNowBatteryUv_init_default {0, 0}
|
||||
#define alox_EspNowBatteryReport_init_default {0, 0, 0, 0, 0}
|
||||
#define alox_EspNowLedRing_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define alox_EspNowOtaStart_init_default {0}
|
||||
@@ -317,6 +328,7 @@ extern "C" {
|
||||
#define alox_EspNowTapConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define alox_EspNowTapEvent_init_zero {0, 0}
|
||||
#define alox_EspNowInputSendMode_init_zero {0, 0}
|
||||
#define alox_EspNowBatteryUv_init_zero {0, 0}
|
||||
#define alox_EspNowBatteryReport_init_zero {0, 0, 0, 0, 0}
|
||||
#define alox_EspNowLedRing_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define alox_EspNowOtaStart_init_zero {0}
|
||||
@@ -370,6 +382,8 @@ extern "C" {
|
||||
#define alox_EspNowTapEvent_kind_tag 2
|
||||
#define alox_EspNowInputSendMode_client_id_tag 1
|
||||
#define alox_EspNowInputSendMode_mode_tag 2
|
||||
#define alox_EspNowBatteryUv_client_id_tag 1
|
||||
#define alox_EspNowBatteryUv_enabled_tag 2
|
||||
#define alox_EspNowBatteryReport_client_id_tag 1
|
||||
#define alox_EspNowBatteryReport_lipo1_valid_tag 2
|
||||
#define alox_EspNowBatteryReport_lipo2_valid_tag 3
|
||||
@@ -416,6 +430,7 @@ extern "C" {
|
||||
#define alox_EspNowMessage_assign_id_tag 23
|
||||
#define alox_EspNowMessage_clear_id_binding_tag 24
|
||||
#define alox_EspNowMessage_input_send_mode_tag 25
|
||||
#define alox_EspNowMessage_battery_uv_tag 26
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define alox_EspNowUnicastTest_FIELDLIST(X, a) \
|
||||
@@ -531,6 +546,12 @@ X(a, STATIC, SINGULAR, UINT32, mode, 2)
|
||||
#define alox_EspNowInputSendMode_CALLBACK NULL
|
||||
#define alox_EspNowInputSendMode_DEFAULT NULL
|
||||
|
||||
#define alox_EspNowBatteryUv_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, client_id, 1) \
|
||||
X(a, STATIC, SINGULAR, BOOL, enabled, 2)
|
||||
#define alox_EspNowBatteryUv_CALLBACK NULL
|
||||
#define alox_EspNowBatteryUv_DEFAULT NULL
|
||||
|
||||
#define alox_EspNowBatteryReport_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, client_id, 1) \
|
||||
X(a, STATIC, SINGULAR, BOOL, lipo1_valid, 2) \
|
||||
@@ -602,7 +623,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload,echo_pong,payload.echo_pong), 21) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,tap_config,payload.tap_config), 22) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,assign_id,payload.assign_id), 23) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,clear_id_binding,payload.clear_id_binding), 24) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,input_send_mode,payload.input_send_mode), 25)
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,input_send_mode,payload.input_send_mode), 25) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,battery_uv,payload.battery_uv), 26)
|
||||
#define alox_EspNowMessage_CALLBACK NULL
|
||||
#define alox_EspNowMessage_DEFAULT NULL
|
||||
#define alox_EspNowMessage_payload_discover_MSGTYPE alox_EspNowDiscover
|
||||
@@ -629,6 +651,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload,input_send_mode,payload.input_send_m
|
||||
#define alox_EspNowMessage_payload_assign_id_MSGTYPE alox_EspNowAssignId
|
||||
#define alox_EspNowMessage_payload_clear_id_binding_MSGTYPE alox_EspNowClearIdBinding
|
||||
#define alox_EspNowMessage_payload_input_send_mode_MSGTYPE alox_EspNowInputSendMode
|
||||
#define alox_EspNowMessage_payload_battery_uv_MSGTYPE alox_EspNowBatteryUv
|
||||
|
||||
extern const pb_msgdesc_t alox_EspNowUnicastTest_msg;
|
||||
extern const pb_msgdesc_t alox_EspNowEchoPing_msg;
|
||||
@@ -647,6 +670,7 @@ extern const pb_msgdesc_t alox_EspNowTapNotify_msg;
|
||||
extern const pb_msgdesc_t alox_EspNowTapConfig_msg;
|
||||
extern const pb_msgdesc_t alox_EspNowTapEvent_msg;
|
||||
extern const pb_msgdesc_t alox_EspNowInputSendMode_msg;
|
||||
extern const pb_msgdesc_t alox_EspNowBatteryUv_msg;
|
||||
extern const pb_msgdesc_t alox_EspNowBatteryReport_msg;
|
||||
extern const pb_msgdesc_t alox_EspNowLedRing_msg;
|
||||
extern const pb_msgdesc_t alox_EspNowOtaStart_msg;
|
||||
@@ -673,6 +697,7 @@ extern const pb_msgdesc_t alox_EspNowMessage_msg;
|
||||
#define alox_EspNowTapConfig_fields &alox_EspNowTapConfig_msg
|
||||
#define alox_EspNowTapEvent_fields &alox_EspNowTapEvent_msg
|
||||
#define alox_EspNowInputSendMode_fields &alox_EspNowInputSendMode_msg
|
||||
#define alox_EspNowBatteryUv_fields &alox_EspNowBatteryUv_msg
|
||||
#define alox_EspNowBatteryReport_fields &alox_EspNowBatteryReport_msg
|
||||
#define alox_EspNowLedRing_fields &alox_EspNowLedRing_msg
|
||||
#define alox_EspNowOtaStart_fields &alox_EspNowOtaStart_msg
|
||||
@@ -691,6 +716,7 @@ extern const pb_msgdesc_t alox_EspNowMessage_msg;
|
||||
#define alox_EspNowAssignId_size 6
|
||||
#define alox_EspNowBatteryQuery_size 6
|
||||
#define alox_EspNowBatteryReport_size 22
|
||||
#define alox_EspNowBatteryUv_size 8
|
||||
#define alox_EspNowClearIdBinding_size 0
|
||||
#define alox_EspNowDiscover_size 19
|
||||
#define alox_EspNowEchoPing_size 22
|
||||
|
||||
@@ -33,6 +33,8 @@ enum EspNowMessageType {
|
||||
ESPNOW_CLEAR_ID_BINDING = 23;
|
||||
/** Master → slave: accel/tap ESP-NOW send path (best_effort/fast/wait/reliable). */
|
||||
ESPNOW_SET_INPUT_SEND_MODE = 24;
|
||||
/** Master → slave: enable/disable software LiPo UV protection (NVS). */
|
||||
ESPNOW_SET_BATTERY_UV = 25;
|
||||
}
|
||||
|
||||
message EspNowUnicastTest {
|
||||
@@ -154,6 +156,12 @@ message EspNowInputSendMode {
|
||||
uint32 mode = 2;
|
||||
}
|
||||
|
||||
/** Master → slave: software LiPo UV protection enable (persisted in NVS). */
|
||||
message EspNowBatteryUv {
|
||||
uint32 client_id = 1; // 0 = all slaves; otherwise only matching slave_id applies
|
||||
bool enabled = 2;
|
||||
}
|
||||
|
||||
/** Slave → master: LiPo voltages (periodic ~30 s and on query). */
|
||||
message EspNowBatteryReport {
|
||||
uint32 client_id = 1;
|
||||
@@ -225,5 +233,6 @@ message EspNowMessage {
|
||||
EspNowAssignId assign_id = 23;
|
||||
EspNowClearIdBinding clear_id_binding = 24;
|
||||
EspNowInputSendMode input_send_mode = 25;
|
||||
EspNowBatteryUv battery_uv = 26;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,12 @@ PB_BIND(alox_InputSendModeRequest, alox_InputSendModeRequest, AUTO)
|
||||
PB_BIND(alox_InputSendModeResponse, alox_InputSendModeResponse, AUTO)
|
||||
|
||||
|
||||
PB_BIND(alox_BatteryUvRequest, alox_BatteryUvRequest, AUTO)
|
||||
|
||||
|
||||
PB_BIND(alox_BatteryUvResponse, alox_BatteryUvResponse, AUTO)
|
||||
|
||||
|
||||
PB_BIND(alox_BatteryStatusRequest, alox_BatteryStatusRequest, AUTO)
|
||||
|
||||
|
||||
|
||||
@@ -48,7 +48,11 @@ typedef enum _alox_MessageType {
|
||||
/* *
|
||||
Host → master: get/set slave ESP-NOW send path for accel/tap
|
||||
(best_effort / fast / wait / reliable). */
|
||||
alox_MessageType_INPUT_SEND_MODE = 35
|
||||
alox_MessageType_INPUT_SEND_MODE = 35,
|
||||
/* *
|
||||
Host → master: get/set software LiPo UV protection enable (NVS per pod).
|
||||
client_id 0 = master; >0 = one slave; all_clients = master + every slave. */
|
||||
alox_MessageType_BATTERY_UV = 36
|
||||
} alox_MessageType;
|
||||
|
||||
/* *
|
||||
@@ -98,6 +102,8 @@ typedef struct _alox_ClientInfo {
|
||||
bool tap_notify_single;
|
||||
bool tap_notify_double;
|
||||
bool tap_notify_triple;
|
||||
/* * Master cache: software UV protection enabled on this slave (NVS on device). */
|
||||
bool uv_protection_enabled;
|
||||
} alox_ClientInfo;
|
||||
|
||||
typedef struct _alox_ClientInfoResponse {
|
||||
@@ -167,6 +173,23 @@ typedef struct _alox_InputSendModeResponse {
|
||||
uint32_t slaves_updated;
|
||||
} alox_InputSendModeResponse;
|
||||
|
||||
/* write=false: read UV enable; write=true: persist enable (and clear latch when disabling).
|
||||
client_id 0 = local master; >0 = one slave; all_clients = master + every registered slave. */
|
||||
typedef struct _alox_BatteryUvRequest {
|
||||
bool write;
|
||||
bool enabled;
|
||||
uint32_t client_id;
|
||||
bool all_clients;
|
||||
} alox_BatteryUvRequest;
|
||||
|
||||
typedef struct _alox_BatteryUvResponse {
|
||||
uint32_t client_id;
|
||||
bool success;
|
||||
bool enabled;
|
||||
bool latched;
|
||||
uint32_t slaves_updated;
|
||||
} alox_BatteryUvResponse;
|
||||
|
||||
/* * Host → master: read LiPo ADC voltages (master local and/or slaves via ESP-NOW). */
|
||||
typedef struct _alox_BatteryStatusRequest {
|
||||
/* * 0 = master only; >0 = one slave; ignored when all_clients */
|
||||
@@ -504,6 +527,8 @@ typedef struct _alox_UartMessage {
|
||||
alox_ClientIdMapResetResponse client_id_map_reset_response;
|
||||
alox_InputSendModeRequest input_send_mode_request;
|
||||
alox_InputSendModeResponse input_send_mode_response;
|
||||
alox_BatteryUvRequest battery_uv_request;
|
||||
alox_BatteryUvResponse battery_uv_response;
|
||||
} payload;
|
||||
} alox_UartMessage;
|
||||
|
||||
@@ -514,8 +539,8 @@ extern "C" {
|
||||
|
||||
/* Helper constants for enums */
|
||||
#define _alox_MessageType_MIN alox_MessageType_UNKNOWN
|
||||
#define _alox_MessageType_MAX alox_MessageType_INPUT_SEND_MODE
|
||||
#define _alox_MessageType_ARRAYSIZE ((alox_MessageType)(alox_MessageType_INPUT_SEND_MODE+1))
|
||||
#define _alox_MessageType_MAX alox_MessageType_BATTERY_UV
|
||||
#define _alox_MessageType_ARRAYSIZE ((alox_MessageType)(alox_MessageType_BATTERY_UV+1))
|
||||
|
||||
#define _alox_InputSendMode_MIN alox_InputSendMode_INPUT_SEND_BEST_EFFORT
|
||||
#define _alox_InputSendMode_MAX alox_InputSendMode_INPUT_SEND_RELIABLE
|
||||
@@ -549,6 +574,8 @@ extern "C" {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define alox_TapEvent_kind_ENUMTYPE alox_TapKind
|
||||
|
||||
|
||||
@@ -587,7 +614,7 @@ extern "C" {
|
||||
#define alox_Ack_init_default {0}
|
||||
#define alox_EchoPayload_init_default {{{NULL}, NULL}}
|
||||
#define alox_VersionResponse_init_default {0, {{NULL}, NULL}, {{NULL}, NULL}}
|
||||
#define alox_ClientInfo_init_default {0, 0, 0, {{NULL}, NULL}, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define alox_ClientInfo_init_default {0, 0, 0, {{NULL}, NULL}, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define alox_ClientInfoResponse_init_default {{{NULL}, NULL}}
|
||||
#define alox_ClientInput_init_default {0, 0, 0, 0}
|
||||
#define alox_ClientInputResponse_init_default {{{NULL}, NULL}}
|
||||
@@ -597,6 +624,8 @@ extern "C" {
|
||||
#define alox_AccelStreamResponse_init_default {0, 0, 0, 0}
|
||||
#define alox_InputSendModeRequest_init_default {0, _alox_InputSendMode_MIN, 0, 0}
|
||||
#define alox_InputSendModeResponse_init_default {0, _alox_InputSendMode_MIN, 0, 0}
|
||||
#define alox_BatteryUvRequest_init_default {0, 0, 0, 0}
|
||||
#define alox_BatteryUvResponse_init_default {0, 0, 0, 0, 0}
|
||||
#define alox_BatteryStatusRequest_init_default {0, 0}
|
||||
#define alox_LipoReading_init_default {0, 0}
|
||||
#define alox_BatterySample_init_default {0, false, alox_LipoReading_init_default, false, alox_LipoReading_init_default, 0}
|
||||
@@ -638,7 +667,7 @@ extern "C" {
|
||||
#define alox_Ack_init_zero {0}
|
||||
#define alox_EchoPayload_init_zero {{{NULL}, NULL}}
|
||||
#define alox_VersionResponse_init_zero {0, {{NULL}, NULL}, {{NULL}, NULL}}
|
||||
#define alox_ClientInfo_init_zero {0, 0, 0, {{NULL}, NULL}, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define alox_ClientInfo_init_zero {0, 0, 0, {{NULL}, NULL}, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define alox_ClientInfoResponse_init_zero {{{NULL}, NULL}}
|
||||
#define alox_ClientInput_init_zero {0, 0, 0, 0}
|
||||
#define alox_ClientInputResponse_init_zero {{{NULL}, NULL}}
|
||||
@@ -648,6 +677,8 @@ extern "C" {
|
||||
#define alox_AccelStreamResponse_init_zero {0, 0, 0, 0}
|
||||
#define alox_InputSendModeRequest_init_zero {0, _alox_InputSendMode_MIN, 0, 0}
|
||||
#define alox_InputSendModeResponse_init_zero {0, _alox_InputSendMode_MIN, 0, 0}
|
||||
#define alox_BatteryUvRequest_init_zero {0, 0, 0, 0}
|
||||
#define alox_BatteryUvResponse_init_zero {0, 0, 0, 0, 0}
|
||||
#define alox_BatteryStatusRequest_init_zero {0, 0}
|
||||
#define alox_LipoReading_init_zero {0, 0}
|
||||
#define alox_BatterySample_init_zero {0, false, alox_LipoReading_init_zero, false, alox_LipoReading_init_zero, 0}
|
||||
@@ -702,6 +733,7 @@ extern "C" {
|
||||
#define alox_ClientInfo_tap_notify_single_tag 9
|
||||
#define alox_ClientInfo_tap_notify_double_tag 10
|
||||
#define alox_ClientInfo_tap_notify_triple_tag 11
|
||||
#define alox_ClientInfo_uv_protection_enabled_tag 12
|
||||
#define alox_ClientInfoResponse_clients_tag 1
|
||||
#define alox_ClientInput_id_tag 1
|
||||
#define alox_ClientInput_lage_x_tag 2
|
||||
@@ -733,6 +765,15 @@ extern "C" {
|
||||
#define alox_InputSendModeResponse_mode_tag 2
|
||||
#define alox_InputSendModeResponse_client_id_tag 3
|
||||
#define alox_InputSendModeResponse_slaves_updated_tag 4
|
||||
#define alox_BatteryUvRequest_write_tag 1
|
||||
#define alox_BatteryUvRequest_enabled_tag 2
|
||||
#define alox_BatteryUvRequest_client_id_tag 3
|
||||
#define alox_BatteryUvRequest_all_clients_tag 4
|
||||
#define alox_BatteryUvResponse_client_id_tag 1
|
||||
#define alox_BatteryUvResponse_success_tag 2
|
||||
#define alox_BatteryUvResponse_enabled_tag 3
|
||||
#define alox_BatteryUvResponse_latched_tag 4
|
||||
#define alox_BatteryUvResponse_slaves_updated_tag 5
|
||||
#define alox_BatteryStatusRequest_client_id_tag 1
|
||||
#define alox_BatteryStatusRequest_all_clients_tag 2
|
||||
#define alox_LipoReading_valid_tag 1
|
||||
@@ -901,6 +942,8 @@ extern "C" {
|
||||
#define alox_UartMessage_client_id_map_reset_response_tag 43
|
||||
#define alox_UartMessage_input_send_mode_request_tag 44
|
||||
#define alox_UartMessage_input_send_mode_response_tag 45
|
||||
#define alox_UartMessage_battery_uv_request_tag 46
|
||||
#define alox_UartMessage_battery_uv_response_tag 47
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define alox_UartMessage_FIELDLIST(X, a) \
|
||||
@@ -944,7 +987,9 @@ X(a, STATIC, ONEOF, MESSAGE, (payload,ble_stream_tick,payload.ble_stream_t
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,client_id_map_reset_request,payload.client_id_map_reset_request), 42) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,client_id_map_reset_response,payload.client_id_map_reset_response), 43) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,input_send_mode_request,payload.input_send_mode_request), 44) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,input_send_mode_response,payload.input_send_mode_response), 45)
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,input_send_mode_response,payload.input_send_mode_response), 45) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,battery_uv_request,payload.battery_uv_request), 46) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,battery_uv_response,payload.battery_uv_response), 47)
|
||||
#define alox_UartMessage_CALLBACK NULL
|
||||
#define alox_UartMessage_DEFAULT NULL
|
||||
#define alox_UartMessage_payload_ack_payload_MSGTYPE alox_Ack
|
||||
@@ -987,6 +1032,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload,input_send_mode_response,payload.inp
|
||||
#define alox_UartMessage_payload_client_id_map_reset_response_MSGTYPE alox_ClientIdMapResetResponse
|
||||
#define alox_UartMessage_payload_input_send_mode_request_MSGTYPE alox_InputSendModeRequest
|
||||
#define alox_UartMessage_payload_input_send_mode_response_MSGTYPE alox_InputSendModeResponse
|
||||
#define alox_UartMessage_payload_battery_uv_request_MSGTYPE alox_BatteryUvRequest
|
||||
#define alox_UartMessage_payload_battery_uv_response_MSGTYPE alox_BatteryUvResponse
|
||||
|
||||
#define alox_Ack_FIELDLIST(X, a) \
|
||||
|
||||
@@ -1016,7 +1063,8 @@ X(a, STATIC, SINGULAR, UINT32, version, 7) \
|
||||
X(a, STATIC, SINGULAR, BOOL, accel_stream_enabled, 8) \
|
||||
X(a, STATIC, SINGULAR, BOOL, tap_notify_single, 9) \
|
||||
X(a, STATIC, SINGULAR, BOOL, tap_notify_double, 10) \
|
||||
X(a, STATIC, SINGULAR, BOOL, tap_notify_triple, 11)
|
||||
X(a, STATIC, SINGULAR, BOOL, tap_notify_triple, 11) \
|
||||
X(a, STATIC, SINGULAR, BOOL, uv_protection_enabled, 12)
|
||||
#define alox_ClientInfo_CALLBACK pb_default_field_callback
|
||||
#define alox_ClientInfo_DEFAULT NULL
|
||||
|
||||
@@ -1089,6 +1137,23 @@ X(a, STATIC, SINGULAR, UINT32, slaves_updated, 4)
|
||||
#define alox_InputSendModeResponse_CALLBACK NULL
|
||||
#define alox_InputSendModeResponse_DEFAULT NULL
|
||||
|
||||
#define alox_BatteryUvRequest_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, BOOL, write, 1) \
|
||||
X(a, STATIC, SINGULAR, BOOL, enabled, 2) \
|
||||
X(a, STATIC, SINGULAR, UINT32, client_id, 3) \
|
||||
X(a, STATIC, SINGULAR, BOOL, all_clients, 4)
|
||||
#define alox_BatteryUvRequest_CALLBACK NULL
|
||||
#define alox_BatteryUvRequest_DEFAULT NULL
|
||||
|
||||
#define alox_BatteryUvResponse_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, client_id, 1) \
|
||||
X(a, STATIC, SINGULAR, BOOL, success, 2) \
|
||||
X(a, STATIC, SINGULAR, BOOL, enabled, 3) \
|
||||
X(a, STATIC, SINGULAR, BOOL, latched, 4) \
|
||||
X(a, STATIC, SINGULAR, UINT32, slaves_updated, 5)
|
||||
#define alox_BatteryUvResponse_CALLBACK NULL
|
||||
#define alox_BatteryUvResponse_DEFAULT NULL
|
||||
|
||||
#define alox_BatteryStatusRequest_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, client_id, 1) \
|
||||
X(a, STATIC, SINGULAR, BOOL, all_clients, 2)
|
||||
@@ -1389,6 +1454,8 @@ extern const pb_msgdesc_t alox_AccelStreamRequest_msg;
|
||||
extern const pb_msgdesc_t alox_AccelStreamResponse_msg;
|
||||
extern const pb_msgdesc_t alox_InputSendModeRequest_msg;
|
||||
extern const pb_msgdesc_t alox_InputSendModeResponse_msg;
|
||||
extern const pb_msgdesc_t alox_BatteryUvRequest_msg;
|
||||
extern const pb_msgdesc_t alox_BatteryUvResponse_msg;
|
||||
extern const pb_msgdesc_t alox_BatteryStatusRequest_msg;
|
||||
extern const pb_msgdesc_t alox_LipoReading_msg;
|
||||
extern const pb_msgdesc_t alox_BatterySample_msg;
|
||||
@@ -1442,6 +1509,8 @@ extern const pb_msgdesc_t alox_OtaSlaveProgressResponse_msg;
|
||||
#define alox_AccelStreamResponse_fields &alox_AccelStreamResponse_msg
|
||||
#define alox_InputSendModeRequest_fields &alox_InputSendModeRequest_msg
|
||||
#define alox_InputSendModeResponse_fields &alox_InputSendModeResponse_msg
|
||||
#define alox_BatteryUvRequest_fields &alox_BatteryUvRequest_msg
|
||||
#define alox_BatteryUvResponse_fields &alox_BatteryUvResponse_msg
|
||||
#define alox_BatteryStatusRequest_fields &alox_BatteryStatusRequest_msg
|
||||
#define alox_LipoReading_fields &alox_LipoReading_msg
|
||||
#define alox_BatterySample_fields &alox_BatterySample_msg
|
||||
@@ -1497,6 +1566,8 @@ extern const pb_msgdesc_t alox_OtaSlaveProgressResponse_msg;
|
||||
#define alox_BatterySample_size 32
|
||||
#define alox_BatteryStatusRequest_size 8
|
||||
#define alox_BatteryStatusResponse_size 580
|
||||
#define alox_BatteryUvRequest_size 12
|
||||
#define alox_BatteryUvResponse_size 18
|
||||
#define alox_BleStreamTick_size 753
|
||||
#define alox_CacheClientAccel_size 26
|
||||
#define alox_CacheClientStatus_size 44
|
||||
|
||||
@@ -47,6 +47,11 @@ enum MessageType {
|
||||
* (best_effort / fast / wait / reliable).
|
||||
*/
|
||||
INPUT_SEND_MODE = 35;
|
||||
/**
|
||||
* Host → master: get/set software LiPo UV protection enable (NVS per pod).
|
||||
* client_id 0 = master; >0 = one slave; all_clients = master + every slave.
|
||||
*/
|
||||
BATTERY_UV = 36;
|
||||
}
|
||||
|
||||
message UartMessage {
|
||||
@@ -92,6 +97,8 @@ message UartMessage {
|
||||
ClientIdMapResetResponse client_id_map_reset_response = 43;
|
||||
InputSendModeRequest input_send_mode_request = 44;
|
||||
InputSendModeResponse input_send_mode_response = 45;
|
||||
BatteryUvRequest battery_uv_request = 46;
|
||||
BatteryUvResponse battery_uv_response = 47;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +129,8 @@ message ClientInfo {
|
||||
bool tap_notify_single = 9;
|
||||
bool tap_notify_double = 10;
|
||||
bool tap_notify_triple = 11;
|
||||
/** Master cache: software UV protection enabled on this slave (NVS on device). */
|
||||
bool uv_protection_enabled = 12;
|
||||
}
|
||||
|
||||
message ClientInfoResponse {
|
||||
@@ -202,6 +211,23 @@ message InputSendModeResponse {
|
||||
uint32 slaves_updated = 4;
|
||||
}
|
||||
|
||||
// write=false: read UV enable; write=true: persist enable (and clear latch when disabling).
|
||||
// client_id 0 = local master; >0 = one slave; all_clients = master + every registered slave.
|
||||
message BatteryUvRequest {
|
||||
bool write = 1;
|
||||
bool enabled = 2;
|
||||
uint32 client_id = 3;
|
||||
bool all_clients = 4;
|
||||
}
|
||||
|
||||
message BatteryUvResponse {
|
||||
uint32 client_id = 1;
|
||||
bool success = 2;
|
||||
bool enabled = 3;
|
||||
bool latched = 4;
|
||||
uint32 slaves_updated = 5;
|
||||
}
|
||||
|
||||
/** Host → master: read LiPo ADC voltages (master local and/or slaves via ESP-NOW). */
|
||||
message BatteryStatusRequest {
|
||||
/** 0 = master only; >0 = one slave; ignored when all_clients */
|
||||
|
||||
Reference in New Issue
Block a user