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:
2026-11-01 22:51:17 +01:00
co-authored by Cursor
parent c3b20887bf
commit 7f28a48a10
33 changed files with 1411 additions and 240 deletions
+78 -7
View File
@@ -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