Add runtime BMA456 tap config with NVS persistence and goTool UI.

Expose multitap parameters over UART/ESP-NOW (like deadzone), store per node in NVS, and allow get/set from CLI, REST, and the dashboard without poll-overwrite while editing.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
simon
2026-09-26 13:07:13 +02:00
co-authored by Cursor
parent f006f8b912
commit d7441cb85f
32 changed files with 1859 additions and 150 deletions
+10
View File
@@ -175,6 +175,7 @@ UART_CMD_REQ(&uart_msg, alox_UartMessage_accel_deadzone_request_tag, accel_deadz
| `ESPNOW_SLAVE_INFO` | S→M | `slave_info` | Erste Registrierung | | `ESPNOW_SLAVE_INFO` | S→M | `slave_info` | Erste Registrierung |
| `ESPNOW_HEARTBEAT` | S→M | `heartbeat` | Keepalive 1 s | | `ESPNOW_HEARTBEAT` | S→M | `heartbeat` | Keepalive 1 s |
| `ESPNOW_SET_ACCEL_DEADZONE` | M→S | `accel_deadzone` | Deadzone LSB | | `ESPNOW_SET_ACCEL_DEADZONE` | M→S | `accel_deadzone` | Deadzone LSB |
| `ESPNOW_SET_TAP_CONFIG` | M→S | `tap_config` | Multitap-Parameter + NVS |
| `ESPNOW_SET_ACCEL_STREAM` | M→S | `accel_stream` | Stream ~16 ms | | `ESPNOW_SET_ACCEL_STREAM` | M→S | `accel_stream` | Stream ~16 ms |
| `ESPNOW_ACCEL_SAMPLE` | S→M | `accel_sample` | x/y/z Roh-LSB | | `ESPNOW_ACCEL_SAMPLE` | S→M | `accel_sample` | x/y/z Roh-LSB |
| `ESPNOW_SET_TAP_NOTIFY` | M→S | `tap_notify` | Tap-Arten filtern | | `ESPNOW_SET_TAP_NOTIFY` | M→S | `tap_notify` | Tap-Arten filtern |
@@ -238,6 +239,7 @@ Nur auf dem **Master** registriert (`powerpod.c`). IDs aus `MessageType` in `uar
| 29 | CACHE_STATUS | `cmd_cache_status.c` | Accel + Tap Cache (ein Round-Trip) | | 29 | CACHE_STATUS | `cmd_cache_status.c` | Accel + Tap Cache (ein Round-Trip) |
| 30 | ESPNOW_ECHO_PING | `cmd_espnow_echo_ping.c` | Timestamp-Echo über ESP-NOW (Latenztest) | | 30 | ESPNOW_ECHO_PING | `cmd_espnow_echo_ping.c` | Timestamp-Echo über ESP-NOW (Latenztest) |
| 31 | SET_LOG_LEVEL | `cmd_set_log_level.c` | ESP-IDF-Log-Level global (`"*"`) lesen/setzen | | 31 | SET_LOG_LEVEL | `cmd_set_log_level.c` | ESP-IDF-Log-Level global (`"*"`) lesen/setzen |
| 32 | TAP_CONFIG | `cmd_tap_config.c` | BMA456 Multitap-Parameter + NVS |
### 7.1 VERSION (3) ### 7.1 VERSION (3)
@@ -264,6 +266,12 @@ Nur auf dem **Master** registriert (`powerpod.c`). IDs aus `MessageType` in `uar
- Konfiguriert auf Slave welche Tap-Arten `ESPNOW_TAP_EVENT` auslösen. - Konfiguriert auf Slave welche Tap-Arten `ESPNOW_TAP_EVENT` auslösen.
- Tap-Quelle: BMA456-Interrupt → `on_bma456_tap` in `esp_now_comm.c`. - Tap-Quelle: BMA456-Interrupt → `on_bma456_tap` in `esp_now_comm.c`.
### 7.5a TAP_CONFIG (32)
- **Request:** `write`, `client_id` (0=lokal), `all_clients`, Multitap-Felder (`tap_sens_thres` … `enable_triple`).
- **Write:** `bma456_set_tap_config` + NVS `tap_cfg` lokal; Slaves via `ESPNOW_SET_TAP_CONFIG`.
- Boot: `pod_settings_apply_tap_config()` nach `init_bma456()`.
### 7.6 CACHE_STATUS (29) ### 7.6 CACHE_STATUS (29)
- **Request:** leer. - **Request:** leer.
@@ -437,6 +445,7 @@ Aktivierbar mit `POWERPOD_BATTERY_UV_ENABLE` in `powerpod.h` (CMake-Override mö
| Key | Inhalt | | Key | Inhalt |
|-----|--------| |-----|--------|
| `accel_dz` | Accel-Deadzone LSB | | `accel_dz` | Accel-Deadzone LSB |
| `tap_cfg` | BMA456 Multitap-Config (Blob) |
| `uv_latch` | Software-UV-Zustand (`1` = Energiesparmodus) | | `uv_latch` | Software-UV-Zustand (`1` = Energiesparmodus) |
Gespeichert bei lokalem Set (UART `client_id=0`, ESP-NOW auf Slave). Geladen nach `init_bma456()`. Gespeichert bei lokalem Set (UART `client_id=0`, ESP-NOW auf Slave). Geladen nach `init_bma456()`.
@@ -492,6 +501,7 @@ Includes in generierten `.pb.c` müssen `"uart_messages.pb.h"` heißen (nicht `m
| `cmd_client_info.c` | CLIENT_INFO | | `cmd_client_info.c` | CLIENT_INFO |
| `cmd_accel_deadzone.c` | ACCEL_DEADZONE | | `cmd_accel_deadzone.c` | ACCEL_DEADZONE |
| `cmd_accel_stream.c` | ACCEL_STREAM | | `cmd_accel_stream.c` | ACCEL_STREAM |
| `cmd_tap_config.c` | TAP_CONFIG |
| `cmd_tap_notify.c` | TAP_NOTIFY | | `cmd_tap_notify.c` | TAP_NOTIFY |
| `cmd_cache_status.c` | CACHE_STATUS | | `cmd_cache_status.c` | CACHE_STATUS |
| `cmd_battery.c` | BATTERY_STATUS | | `cmd_battery.c` | BATTERY_STATUS |
+3
View File
@@ -25,6 +25,7 @@ go run . -port /dev/ttyUSB0 clients
| `version` | `0x03` | Prints `version` and `git_hash` from firmware | | `version` | `0x03` | Prints `version` and `git_hash` from firmware |
| `clients` | `0x04` | Lists slaves registered on the master via ESP-NOW | | `clients` | `0x04` | Lists slaves registered on the master via ESP-NOW |
| `deadzone` | `0x06` | Get/set accelerometer deadzone LSB (`-set`, `-value`, `-client`, `-all`) | | `deadzone` | `0x06` | Get/set accelerometer deadzone LSB (`-set`, `-value`, `-client`, `-all`) |
| `tap-config` | `0x20` | Get/set BMA456 tap detection params (`-set`, `-client`, `-all`, `-sens`, `-max-gest`, `-shock`, `-quiet`, `-wait`, `-axis`, `-single`, `-double`, `-triple`) |
| `tap-notify` | `0x1b` | Get/set which tap kinds (single/double/triple) notify via ESP-NOW (`-set`, `-client`, `-all`, `-single`, `-double`, `-triple`) | | `tap-notify` | `0x1b` | Get/set which tap kinds (single/double/triple) notify via ESP-NOW (`-set`, `-client`, `-all`, `-single`, `-double`, `-triple`) |
| `cache-status` | `0x1d` | Subscribed accel + tap cache (`CACHE_STATUS`); one UART round-trip for 16 ms polling | | `cache-status` | `0x1d` | Subscribed accel + tap cache (`CACHE_STATUS`); one UART round-trip for 16 ms polling |
| `unicast-test` | `0x07` | Sends ESP-NOW unicast test to one slave (`-client`, `-seq`) | | `unicast-test` | `0x07` | Sends ESP-NOW unicast test to one slave (`-client`, `-seq`) |
@@ -94,6 +95,8 @@ If the UART device is unplugged or the port disappears, `serve` keeps running an
CLI: CLI:
```bash ```bash
go run . -port /dev/ttyUSB0 tap-config
go run . -port /dev/ttyUSB0 tap-config -set -sens 5 -axis 2
go run . -port /dev/ttyUSB0 tap-notify -client 16 -set -single go run . -port /dev/ttyUSB0 tap-notify -client 16 -set -single
go run . -port /dev/ttyUSB0 cache-status go run . -port /dev/ttyUSB0 cache-status
``` ```
+1
View File
@@ -96,6 +96,7 @@ func mountServeAPI(mux *http.ServeMux, link *managedSerial, hub *wsHub, streamCt
mountLiveStreamAPI(mux, hub) mountLiveStreamAPI(mux, hub)
mountAccelStreamAPI(mux, link, hub, streamCtl) mountAccelStreamAPI(mux, link, hub, streamCtl)
mountTapAPI(mux, link, hub, tapCtl) mountTapAPI(mux, link, hub, tapCtl)
mountTapConfigAPI(mux, link)
mountLedRingAPI(mux, link) mountLedRingAPI(mux, link)
mountBatteryAPI(mux, link) mountBatteryAPI(mux, link)
mux.HandleFunc("/api/deadzone", func(w http.ResponseWriter, r *http.Request) { mux.HandleFunc("/api/deadzone", func(w http.ResponseWriter, r *http.Request) {
+171
View File
@@ -0,0 +1,171 @@
package main
import (
"encoding/json"
"fmt"
"net/http"
"powerpod/gotool/pb"
)
type tapConfigFields struct {
TapSensThres uint32 `json:"tap_sens_thres"`
MaxGestDur uint32 `json:"max_gest_dur"`
TapShockDur uint32 `json:"tap_shock_dur"`
QuiteTimeAfterGest uint32 `json:"quite_time_after_gest"`
WaitForTimeout uint32 `json:"wait_for_timeout"`
AxisSel uint32 `json:"axis_sel"`
EnableSingle bool `json:"enable_single"`
EnableDouble bool `json:"enable_double"`
EnableTriple bool `json:"enable_triple"`
}
type tapConfigAPIResponse struct {
tapConfigFields
ClientID uint32 `json:"client_id"`
Success bool `json:"success"`
SlavesUpdated uint32 `json:"slaves_updated"`
Error string `json:"error,omitempty"`
}
type tapConfigAPIRequest struct {
Write bool `json:"write"`
ClientID uint32 `json:"client_id"`
AllClients bool `json:"all_clients"`
// SlavesOnly: with all_clients, push to ESP-NOW slaves only (master BMA456 unchanged).
SlavesOnly bool `json:"slaves_only"`
tapConfigFields
}
func tapConfigFieldsFromPB(r *pb.TapConfigResponse) tapConfigFields {
return tapConfigFields{
TapSensThres: r.GetTapSensThres(),
MaxGestDur: r.GetMaxGestDur(),
TapShockDur: r.GetTapShockDur(),
QuiteTimeAfterGest: r.GetQuiteTimeAfterGest(),
WaitForTimeout: r.GetWaitForTimeout(),
AxisSel: r.GetAxisSel(),
EnableSingle: r.GetEnableSingle(),
EnableDouble: r.GetEnableDouble(),
EnableTriple: r.GetEnableTriple(),
}
}
func (f tapConfigFields) toPBRequest(write bool, clientID uint32, all bool) *pb.TapConfigRequest {
return &pb.TapConfigRequest{
Write: write,
ClientId: clientID,
AllClients: all,
TapSensThres: f.TapSensThres,
MaxGestDur: f.MaxGestDur,
TapShockDur: f.TapShockDur,
QuiteTimeAfterGest: f.QuiteTimeAfterGest,
WaitForTimeout: f.WaitForTimeout,
AxisSel: f.AxisSel,
EnableSingle: f.EnableSingle,
EnableDouble: f.EnableDouble,
EnableTriple: f.EnableTriple,
}
}
func mountTapConfigAPI(mux *http.ServeMux, link *managedSerial) {
mux.HandleFunc("/api/tap-config", func(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
serveTapConfigGet(w, r, link)
case http.MethodPost:
serveTapConfigPost(w, r, link)
default:
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
}
})
}
func serveTapConfigGet(w http.ResponseWriter, r *http.Request, link *managedSerial) {
clientID, err := parseUintQuery(r, "client_id", 0)
if err != nil {
writeJSON(w, http.StatusBadRequest, tapConfigAPIResponse{Error: err.Error()})
return
}
resp, err := link.TapConfig(&pb.TapConfigRequest{
Write: false,
ClientId: clientID,
})
if err != nil {
writeJSON(w, http.StatusServiceUnavailable, tapConfigAPIResponse{
ClientID: clientID,
Error: err.Error(),
})
return
}
out := tapConfigAPIResponse{
tapConfigFields: tapConfigFieldsFromPB(resp),
ClientID: resp.GetClientId(),
Success: resp.GetSuccess(),
}
writeJSON(w, http.StatusOK, out)
}
func serveTapConfigPost(w http.ResponseWriter, r *http.Request, link *managedSerial) {
var body tapConfigAPIRequest
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
writeJSON(w, http.StatusBadRequest, tapConfigAPIResponse{Error: "invalid JSON"})
return
}
if body.AllClients && body.SlavesOnly {
updated, err := applyTapConfigToSlaves(link, body.tapConfigFields)
if err != nil {
writeJSON(w, http.StatusServiceUnavailable, tapConfigAPIResponse{
tapConfigFields: body.tapConfigFields,
Error: err.Error(),
})
return
}
writeJSON(w, http.StatusOK, tapConfigAPIResponse{
tapConfigFields: body.tapConfigFields,
Success: updated > 0,
SlavesUpdated: updated,
})
return
}
resp, err := link.TapConfig(body.tapConfigFields.toPBRequest(true, body.ClientID, body.AllClients))
if err != nil {
writeJSON(w, http.StatusServiceUnavailable, tapConfigAPIResponse{
ClientID: body.ClientID,
tapConfigFields: body.tapConfigFields,
Error: err.Error(),
})
return
}
writeJSON(w, http.StatusOK, tapConfigAPIResponse{
tapConfigFields: tapConfigFieldsFromPB(resp),
ClientID: resp.GetClientId(),
Success: resp.GetSuccess(),
SlavesUpdated: resp.GetSlavesUpdated(),
})
}
func applyTapConfigToSlaves(link *managedSerial, fields tapConfigFields) (uint32, error) {
clients, err := link.listClients()
if err != nil {
return 0, err
}
var updated uint32
for _, c := range clients {
resp, err := link.TapConfig(fields.toPBRequest(true, c.GetId(), false))
if err != nil {
continue
}
if resp.GetSuccess() {
updated++
}
}
if len(clients) == 0 {
return 0, fmt.Errorf("no slaves registered")
}
if updated == 0 {
return 0, fmt.Errorf("tap config not applied to any slave")
}
return updated, nil
}
+52
View File
@@ -225,6 +225,27 @@ func (m *managedSerial) AccelDeadzonePoll(req *pb.AccelDeadzoneRequest) (*pb.Acc
return m.accelDeadzoneVia(m.withPortPoll, req) return m.accelDeadzoneVia(m.withPortPoll, req)
} }
func (m *managedSerial) TapConfig(req *pb.TapConfigRequest) (*pb.TapConfigResponse, error) {
return m.tapConfigVia(m.withPort, req)
}
func (m *managedSerial) TapConfigPoll(req *pb.TapConfigRequest) (*pb.TapConfigResponse, error) {
return m.tapConfigVia(m.withPortPoll, req)
}
func (m *managedSerial) tapConfigVia(
portFn func(func(*serialPort) error) error,
req *pb.TapConfigRequest,
) (*pb.TapConfigResponse, error) {
var resp *pb.TapConfigResponse
err := portFn(func(sp *serialPort) error {
var e error
resp, e = sp.TapConfig(req)
return e
})
return resp, err
}
func (m *managedSerial) accelDeadzoneVia( func (m *managedSerial) accelDeadzoneVia(
portFn func(func(*serialPort) error) error, portFn func(func(*serialPort) error) error,
req *pb.AccelDeadzoneRequest, req *pb.AccelDeadzoneRequest,
@@ -383,6 +404,33 @@ func (s *serialPort) accelDeadzone(req *pb.AccelDeadzoneRequest) (*pb.AccelDeadz
return r, nil return r, nil
} }
func (s *serialPort) tapConfig(req *pb.TapConfigRequest) (*pb.TapConfigResponse, error) {
msg := &pb.UartMessage{
Type: pb.MessageType_TAP_CONFIG,
Payload: &pb.UartMessage_TapConfigRequest{
TapConfigRequest: req,
},
}
body, err := proto.Marshal(msg)
if err != nil {
return nil, fmt.Errorf("encode: %w", err)
}
payload := append([]byte{byte(pb.MessageType_TAP_CONFIG)}, body...)
respPayload, err := s.exchangePayload(payload, "TAP_CONFIG")
if err != nil {
return nil, err
}
var respMsg pb.UartMessage
if err := proto.Unmarshal(respPayload[1:], &respMsg); err != nil {
return nil, fmt.Errorf("decode: %w", err)
}
r := respMsg.GetTapConfigResponse()
if r == nil {
return nil, fmt.Errorf("missing tap_config_response")
}
return r, nil
}
func (s *serialPort) espnowUnicastTest(clientID, seq uint32) (*pb.EspNowUnicastTestResponse, error) { func (s *serialPort) espnowUnicastTest(clientID, seq uint32) (*pb.EspNowUnicastTestResponse, error) {
req := &pb.EspNowUnicastTestRequest{ClientId: clientID, Seq: seq} req := &pb.EspNowUnicastTestRequest{ClientId: clientID, Seq: seq}
msg := &pb.UartMessage{ msg := &pb.UartMessage{
@@ -557,6 +605,10 @@ func (s *serialPort) AccelDeadzone(req *pb.AccelDeadzoneRequest) (*pb.AccelDeadz
return s.accelDeadzone(req) return s.accelDeadzone(req)
} }
func (s *serialPort) TapConfig(req *pb.TapConfigRequest) (*pb.TapConfigResponse, error) {
return s.tapConfig(req)
}
func (s *serialPort) EspnowUnicastTest(clientID, seq uint32) (*pb.EspNowUnicastTestResponse, error) { func (s *serialPort) EspnowUnicastTest(clientID, seq uint32) (*pb.EspNowUnicastTestResponse, error) {
return s.espnowUnicastTest(clientID, seq) return s.espnowUnicastTest(clientID, seq)
} }
+54
View File
@@ -0,0 +1,54 @@
package main
import (
"flag"
"fmt"
"powerpod/gotool/pb"
)
func runTapConfig(sp *serialPort, args []string) error {
fs := flag.NewFlagSet("tap-config", flag.ExitOnError)
write := fs.Bool("set", false, "write tap config (default: read)")
clientID := fs.Uint("client", 0, "client id (0=local master BMA456)")
all := fs.Bool("all", false, "apply to all registered slaves (master only)")
sens := fs.Uint("sens", 5, "tap_sens_thres 0=most … 15=least")
maxGest := fs.Uint("max-gest", 100, "max_gest_dur (×5 ms)")
shock := fs.Uint("shock", 6, "tap_shock_dur (×5 ms)")
quiet := fs.Uint("quiet", 60, "quite_time_after_gest (×5 ms)")
wait := fs.Uint("wait", 0, "wait_for_timeout 0|1")
axis := fs.Uint("axis", 2, "axis_sel 0=X 1=Y 2=Z")
single := fs.Bool("single", true, "enable single tap")
doubleTap := fs.Bool("double", true, "enable double tap")
triple := fs.Bool("triple", true, "enable triple tap")
if err := fs.Parse(args); err != nil {
return err
}
r, err := sp.tapConfig(&pb.TapConfigRequest{
Write: *write,
ClientId: uint32(*clientID),
AllClients: *all,
TapSensThres: uint32(*sens),
MaxGestDur: uint32(*maxGest),
TapShockDur: uint32(*shock),
QuiteTimeAfterGest: uint32(*quiet),
WaitForTimeout: uint32(*wait),
AxisSel: uint32(*axis),
EnableSingle: *single,
EnableDouble: *doubleTap,
EnableTriple: *triple,
})
if err != nil {
return err
}
fmt.Printf("client_id=%d success=%v slaves_updated=%d\n",
r.GetClientId(), r.GetSuccess(), r.GetSlavesUpdated())
fmt.Printf(" sens=%d max_gest=%d shock=%d quiet=%d wait=%d axis=%d\n",
r.GetTapSensThres(), r.GetMaxGestDur(), r.GetTapShockDur(),
r.GetQuiteTimeAfterGest(), r.GetWaitForTimeout(), r.GetAxisSel())
fmt.Printf(" enable single=%v double=%v triple=%v\n",
r.GetEnableSingle(), r.GetEnableDouble(), r.GetEnableTriple())
return nil
}
+48
View File
@@ -19,6 +19,7 @@ type MasterView struct {
GitHash string `json:"git_hash"` GitHash string `json:"git_hash"`
RunningPartition string `json:"running_partition,omitempty"` RunningPartition string `json:"running_partition,omitempty"`
Deadzone uint32 `json:"deadzone,omitempty"` Deadzone uint32 `json:"deadzone,omitempty"`
TapConfig *TapConfigView `json:"tap_config,omitempty"`
Lipo1 lipoReadingJSON `json:"lipo1"` Lipo1 lipoReadingJSON `json:"lipo1"`
Lipo2 lipoReadingJSON `json:"lipo2"` Lipo2 lipoReadingJSON `json:"lipo2"`
BatteryAgeMs uint32 `json:"battery_age_ms,omitempty"` BatteryAgeMs uint32 `json:"battery_age_ms,omitempty"`
@@ -26,11 +27,24 @@ type MasterView struct {
Error string `json:"error,omitempty"` Error string `json:"error,omitempty"`
} }
type TapConfigView struct {
TapSensThres uint32 `json:"tap_sens_thres"`
MaxGestDur uint32 `json:"max_gest_dur"`
TapShockDur uint32 `json:"tap_shock_dur"`
QuiteTimeAfterGest uint32 `json:"quite_time_after_gest"`
WaitForTimeout uint32 `json:"wait_for_timeout"`
AxisSel uint32 `json:"axis_sel"`
EnableSingle bool `json:"enable_single"`
EnableDouble bool `json:"enable_double"`
EnableTriple bool `json:"enable_triple"`
}
type ClientView struct { type ClientView struct {
ID uint32 `json:"id"` ID uint32 `json:"id"`
MAC string `json:"mac"` MAC string `json:"mac"`
Version uint32 `json:"version"` Version uint32 `json:"version"`
Deadzone uint32 `json:"deadzone,omitempty"` Deadzone uint32 `json:"deadzone,omitempty"`
TapConfig *TapConfigView `json:"tap_config,omitempty"`
Available bool `json:"available"` Available bool `json:"available"`
Used bool `json:"used"` Used bool `json:"used"`
LastPing uint32 `json:"last_ping"` LastPing uint32 `json:"last_ping"`
@@ -540,6 +554,9 @@ func pollDashboard(link *managedSerial, portName string, last *DashboardState, s
if dz, err := readDeadzonePoll(link, 0); err == nil { if dz, err := readDeadzonePoll(link, 0); err == nil {
st.Master.Deadzone = dz st.Master.Deadzone = dz
} }
if tc, err := readTapConfigPoll(link, 0); err == nil {
st.Master.TapConfig = tc
}
clients, err := link.listClientsPoll() clients, err := link.listClientsPoll()
if err != nil { if err != nil {
@@ -574,6 +591,9 @@ func pollDashboard(link *managedSerial, portName string, last *DashboardState, s
if dz, err := readDeadzonePoll(link, c.GetId()); err == nil { if dz, err := readDeadzonePoll(link, c.GetId()); err == nil {
st.Clients[i].Deadzone = dz st.Clients[i].Deadzone = dz
} }
if tc, err := readTapConfigPoll(link, c.GetId()); err == nil {
st.Clients[i].TapConfig = tc
}
} }
} }
if last != nil { if last != nil {
@@ -714,6 +734,34 @@ func readDeadzonePoll(link *managedSerial, clientID uint32) (uint32, error) {
return r.GetDeadzone(), nil return r.GetDeadzone(), nil
} }
func tapConfigViewFromPB(r *pb.TapConfigResponse) *TapConfigView {
return &TapConfigView{
TapSensThres: r.GetTapSensThres(),
MaxGestDur: r.GetMaxGestDur(),
TapShockDur: r.GetTapShockDur(),
QuiteTimeAfterGest: r.GetQuiteTimeAfterGest(),
WaitForTimeout: r.GetWaitForTimeout(),
AxisSel: r.GetAxisSel(),
EnableSingle: r.GetEnableSingle(),
EnableDouble: r.GetEnableDouble(),
EnableTriple: r.GetEnableTriple(),
}
}
func readTapConfigPoll(link *managedSerial, clientID uint32) (*TapConfigView, error) {
r, err := link.TapConfigPoll(&pb.TapConfigRequest{
Write: false,
ClientId: clientID,
})
if err != nil {
return nil, err
}
if !r.GetSuccess() {
return nil, fmt.Errorf("tap config read failed for client %d", clientID)
}
return tapConfigViewFromPB(r), nil
}
func formatMAC(mac []byte) string { func formatMAC(mac []byte) string {
if len(mac) == 0 { if len(mac) == 0 {
return "" return ""
+42
View File
@@ -209,6 +209,46 @@ With `all_clients` + `slaves_only`: push to ESP-NOW slaves only (master BMA456 u
{"deadzone": 128, "client_id": 0, "success": true, "slaves_updated": 2} {"deadzone": 128, "client_id": 0, "success": true, "slaves_updated": 2}
``` ```
### Tap config (BMA456 multitap)
```http
GET /api/tap-config?client_id=0
POST /api/tap-config
Content-Type: application/json
{
"write": true,
"client_id": 0,
"tap_sens_thres": 5,
"max_gest_dur": 100,
"tap_shock_dur": 6,
"quite_time_after_gest": 60,
"wait_for_timeout": 0,
"axis_sel": 2,
"enable_single": true,
"enable_double": true,
"enable_triple": true
}
```
Same `client_id` / `all_clients` / `slaves_only` semantics as deadzone. Values are applied to the sensor and persisted in NVS on each target node.
```json
{
"client_id": 0,
"success": true,
"slaves_updated": 0,
"tap_sens_thres": 5,
"max_gest_dur": 100,
"tap_shock_dur": 6,
"quite_time_after_gest": 60,
"wait_for_timeout": 0,
"axis_sel": 2,
"enable_single": true,
"enable_double": true,
"enable_triple": true
}
```
### Unicast test ### Unicast test
```http ```http
@@ -361,6 +401,8 @@ Same as external API:
| Nur Master deadzone | `POST /api/deadzone` `client_id: 0` or CLI `deadzone -set -client 0` | | Nur Master deadzone | `POST /api/deadzone` `client_id: 0` or CLI `deadzone -set -client 0` |
| Einzelner Slave | `client_id: <id>` | | Einzelner Slave | `client_id: <id>` |
| Alle Slaves deadzone | `all_clients` + `slaves_only` on POST | | Alle Slaves deadzone | `all_clients` + `slaves_only` on POST |
| Master tap config | `GET` / `POST /api/tap-config` `client_id: 0` or CLI `tap-config` |
| Tap-Cfg alle Slaves | `POST /api/tap-config` with `all_clients` + `slaves_only` |
| Unicast test | `POST /api/unicast-test` | | Unicast test | `POST /api/unicast-test` |
| Echo ping | `POST /api/echo-ping` (per-slave latency; UI shows Host ms + ESP ms) | | Echo ping | `POST /api/echo-ping` (per-slave latency; UI shows Host ms + ESP ms) |
| Master log level | `GET` / `POST /api/log-level` or CLI `log-level` | | Master log level | `GET` / `POST /api/log-level` or CLI `log-level` |
+4 -1
View File
@@ -16,6 +16,7 @@ func usage() {
fmt.Fprintf(os.Stderr, " version firmware version and git hash\n") fmt.Fprintf(os.Stderr, " version firmware version and git hash\n")
fmt.Fprintf(os.Stderr, " clients registered ESP-NOW slaves on the master\n") fmt.Fprintf(os.Stderr, " clients registered ESP-NOW slaves on the master\n")
fmt.Fprintf(os.Stderr, " deadzone get/set accelerometer deadzone (LSB)\n") fmt.Fprintf(os.Stderr, " deadzone get/set accelerometer deadzone (LSB)\n")
fmt.Fprintf(os.Stderr, " tap-config get/set BMA456 tap detection parameters\n")
fmt.Fprintf(os.Stderr, " tap-notify get/set which tap kinds notify via ESP-NOW\n") fmt.Fprintf(os.Stderr, " tap-notify get/set which tap kinds notify via ESP-NOW\n")
fmt.Fprintf(os.Stderr, " cache-status subscribed accel + tap cache (one UART round-trip)\n") fmt.Fprintf(os.Stderr, " cache-status subscribed accel + tap cache (one UART round-trip)\n")
fmt.Fprintf(os.Stderr, " unicast-test send ESP-NOW unicast test to one slave\n") fmt.Fprintf(os.Stderr, " unicast-test send ESP-NOW unicast test to one slave\n")
@@ -54,7 +55,7 @@ func main() {
os.Exit(2) os.Exit(2)
} }
runErr = runServe(*portName, *baud, flag.Args()[1:]) runErr = runServe(*portName, *baud, flag.Args()[1:])
case "version", "clients", "client-info", "deadzone", "accel-deadzone", "tap-notify", "tap_notify", "cache-status", "cache_status", "unicast-test", "unicast_test", "echo-ping", "echo_ping", "led-ring", "led_ring", "find-me", "find_me", "restart", "log-level", "log_level", "ota", "ota-progress", "ota_progress": case "version", "clients", "client-info", "deadzone", "accel-deadzone", "tap-config", "tap_config", "tap-notify", "tap_notify", "cache-status", "cache_status", "unicast-test", "unicast_test", "echo-ping", "echo_ping", "led-ring", "led_ring", "find-me", "find_me", "restart", "log-level", "log_level", "ota", "ota-progress", "ota_progress":
if *portName == "" { if *portName == "" {
fmt.Fprintf(os.Stderr, "command %q requires -port\n\n", cmd) fmt.Fprintf(os.Stderr, "command %q requires -port\n\n", cmd)
usage() usage()
@@ -74,6 +75,8 @@ func main() {
runErr = runClients(sp) runErr = runClients(sp)
case "deadzone", "accel-deadzone": case "deadzone", "accel-deadzone":
runErr = runDeadzone(sp, flag.Args()[1:]) runErr = runDeadzone(sp, flag.Args()[1:])
case "tap-config", "tap_config":
runErr = runTapConfig(sp, flag.Args()[1:])
case "tap-notify", "tap_notify": case "tap-notify", "tap_notify":
runErr = runTapNotify(sp, flag.Args()[1:]) runErr = runTapNotify(sp, flag.Args()[1:])
case "cache-status", "cache_status": case "cache-status", "cache_status":
+401 -58
View File
@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.36.11 // protoc-gen-go v1.36.11
// protoc v7.34.1 // protoc v7.36.0
// source: uart_messages.proto // source: uart_messages.proto
package pb package pb
@@ -50,6 +50,8 @@ const (
MessageType_ESPNOW_ECHO_PING MessageType = 30 MessageType_ESPNOW_ECHO_PING MessageType = 30
// * Host → master: get/set ESP-IDF log level for tag "*" (global). // * Host → master: get/set ESP-IDF log level for tag "*" (global).
MessageType_SET_LOG_LEVEL MessageType = 31 MessageType_SET_LOG_LEVEL MessageType = 31
// * Host → master: get/set BMA456H multitap detection parameters.
MessageType_TAP_CONFIG MessageType = 32
) )
// Enum value maps for MessageType. // Enum value maps for MessageType.
@@ -78,6 +80,7 @@ var (
29: "CACHE_STATUS", 29: "CACHE_STATUS",
30: "ESPNOW_ECHO_PING", 30: "ESPNOW_ECHO_PING",
31: "SET_LOG_LEVEL", 31: "SET_LOG_LEVEL",
32: "TAP_CONFIG",
} }
MessageType_value = map[string]int32{ MessageType_value = map[string]int32{
"UNKNOWN": 0, "UNKNOWN": 0,
@@ -103,6 +106,7 @@ var (
"CACHE_STATUS": 29, "CACHE_STATUS": 29,
"ESPNOW_ECHO_PING": 30, "ESPNOW_ECHO_PING": 30,
"SET_LOG_LEVEL": 31, "SET_LOG_LEVEL": 31,
"TAP_CONFIG": 32,
} }
) )
@@ -223,6 +227,8 @@ type UartMessage struct {
// *UartMessage_EspnowEchoPingResponse // *UartMessage_EspnowEchoPingResponse
// *UartMessage_SetLogLevelRequest // *UartMessage_SetLogLevelRequest
// *UartMessage_SetLogLevelResponse // *UartMessage_SetLogLevelResponse
// *UartMessage_TapConfigRequest
// *UartMessage_TapConfigResponse
Payload isUartMessage_Payload `protobuf_oneof:"payload"` Payload isUartMessage_Payload `protobuf_oneof:"payload"`
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@@ -569,6 +575,24 @@ func (x *UartMessage) GetSetLogLevelResponse() *SetLogLevelResponse {
return nil return nil
} }
func (x *UartMessage) GetTapConfigRequest() *TapConfigRequest {
if x != nil {
if x, ok := x.Payload.(*UartMessage_TapConfigRequest); ok {
return x.TapConfigRequest
}
}
return nil
}
func (x *UartMessage) GetTapConfigResponse() *TapConfigResponse {
if x != nil {
if x, ok := x.Payload.(*UartMessage_TapConfigResponse); ok {
return x.TapConfigResponse
}
}
return nil
}
type isUartMessage_Payload interface { type isUartMessage_Payload interface {
isUartMessage_Payload() isUartMessage_Payload()
} }
@@ -705,6 +729,14 @@ type UartMessage_SetLogLevelResponse struct {
SetLogLevelResponse *SetLogLevelResponse `protobuf:"bytes,38,opt,name=set_log_level_response,json=setLogLevelResponse,proto3,oneof"` SetLogLevelResponse *SetLogLevelResponse `protobuf:"bytes,38,opt,name=set_log_level_response,json=setLogLevelResponse,proto3,oneof"`
} }
type UartMessage_TapConfigRequest struct {
TapConfigRequest *TapConfigRequest `protobuf:"bytes,39,opt,name=tap_config_request,json=tapConfigRequest,proto3,oneof"`
}
type UartMessage_TapConfigResponse struct {
TapConfigResponse *TapConfigResponse `protobuf:"bytes,40,opt,name=tap_config_response,json=tapConfigResponse,proto3,oneof"`
}
func (*UartMessage_AckPayload) isUartMessage_Payload() {} func (*UartMessage_AckPayload) isUartMessage_Payload() {}
func (*UartMessage_EchoPayload) isUartMessage_Payload() {} func (*UartMessage_EchoPayload) isUartMessage_Payload() {}
@@ -771,6 +803,10 @@ func (*UartMessage_SetLogLevelRequest) isUartMessage_Payload() {}
func (*UartMessage_SetLogLevelResponse) isUartMessage_Payload() {} func (*UartMessage_SetLogLevelResponse) isUartMessage_Payload() {}
func (*UartMessage_TapConfigRequest) isUartMessage_Payload() {}
func (*UartMessage_TapConfigResponse) isUartMessage_Payload() {}
type Ack struct { type Ack struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
@@ -3051,6 +3087,272 @@ func (x *SetLogLevelResponse) GetLevel() uint32 {
return 0 return 0
} }
// write=false: read tap config; write=true: apply + persist on target node.
// client_id 0 = local BMA456; >0 = slave id on master; all_clients = push to all slaves.
type TapConfigRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Write bool `protobuf:"varint,1,opt,name=write,proto3" json:"write,omitempty"`
ClientId uint32 `protobuf:"varint,2,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"`
AllClients bool `protobuf:"varint,3,opt,name=all_clients,json=allClients,proto3" json:"all_clients,omitempty"`
TapSensThres uint32 `protobuf:"varint,4,opt,name=tap_sens_thres,json=tapSensThres,proto3" json:"tap_sens_thres,omitempty"`
MaxGestDur uint32 `protobuf:"varint,5,opt,name=max_gest_dur,json=maxGestDur,proto3" json:"max_gest_dur,omitempty"`
TapShockDur uint32 `protobuf:"varint,6,opt,name=tap_shock_dur,json=tapShockDur,proto3" json:"tap_shock_dur,omitempty"`
QuiteTimeAfterGest uint32 `protobuf:"varint,7,opt,name=quite_time_after_gest,json=quiteTimeAfterGest,proto3" json:"quite_time_after_gest,omitempty"`
WaitForTimeout uint32 `protobuf:"varint,8,opt,name=wait_for_timeout,json=waitForTimeout,proto3" json:"wait_for_timeout,omitempty"`
AxisSel uint32 `protobuf:"varint,9,opt,name=axis_sel,json=axisSel,proto3" json:"axis_sel,omitempty"`
EnableSingle bool `protobuf:"varint,10,opt,name=enable_single,json=enableSingle,proto3" json:"enable_single,omitempty"`
EnableDouble bool `protobuf:"varint,11,opt,name=enable_double,json=enableDouble,proto3" json:"enable_double,omitempty"`
EnableTriple bool `protobuf:"varint,12,opt,name=enable_triple,json=enableTriple,proto3" json:"enable_triple,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TapConfigRequest) Reset() {
*x = TapConfigRequest{}
mi := &file_uart_messages_proto_msgTypes[37]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TapConfigRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TapConfigRequest) ProtoMessage() {}
func (x *TapConfigRequest) ProtoReflect() protoreflect.Message {
mi := &file_uart_messages_proto_msgTypes[37]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TapConfigRequest.ProtoReflect.Descriptor instead.
func (*TapConfigRequest) Descriptor() ([]byte, []int) {
return file_uart_messages_proto_rawDescGZIP(), []int{37}
}
func (x *TapConfigRequest) GetWrite() bool {
if x != nil {
return x.Write
}
return false
}
func (x *TapConfigRequest) GetClientId() uint32 {
if x != nil {
return x.ClientId
}
return 0
}
func (x *TapConfigRequest) GetAllClients() bool {
if x != nil {
return x.AllClients
}
return false
}
func (x *TapConfigRequest) GetTapSensThres() uint32 {
if x != nil {
return x.TapSensThres
}
return 0
}
func (x *TapConfigRequest) GetMaxGestDur() uint32 {
if x != nil {
return x.MaxGestDur
}
return 0
}
func (x *TapConfigRequest) GetTapShockDur() uint32 {
if x != nil {
return x.TapShockDur
}
return 0
}
func (x *TapConfigRequest) GetQuiteTimeAfterGest() uint32 {
if x != nil {
return x.QuiteTimeAfterGest
}
return 0
}
func (x *TapConfigRequest) GetWaitForTimeout() uint32 {
if x != nil {
return x.WaitForTimeout
}
return 0
}
func (x *TapConfigRequest) GetAxisSel() uint32 {
if x != nil {
return x.AxisSel
}
return 0
}
func (x *TapConfigRequest) GetEnableSingle() bool {
if x != nil {
return x.EnableSingle
}
return false
}
func (x *TapConfigRequest) GetEnableDouble() bool {
if x != nil {
return x.EnableDouble
}
return false
}
func (x *TapConfigRequest) GetEnableTriple() bool {
if x != nil {
return x.EnableTriple
}
return false
}
type TapConfigResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
ClientId uint32 `protobuf:"varint,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"`
Success bool `protobuf:"varint,2,opt,name=success,proto3" json:"success,omitempty"`
SlavesUpdated uint32 `protobuf:"varint,3,opt,name=slaves_updated,json=slavesUpdated,proto3" json:"slaves_updated,omitempty"`
TapSensThres uint32 `protobuf:"varint,4,opt,name=tap_sens_thres,json=tapSensThres,proto3" json:"tap_sens_thres,omitempty"`
MaxGestDur uint32 `protobuf:"varint,5,opt,name=max_gest_dur,json=maxGestDur,proto3" json:"max_gest_dur,omitempty"`
TapShockDur uint32 `protobuf:"varint,6,opt,name=tap_shock_dur,json=tapShockDur,proto3" json:"tap_shock_dur,omitempty"`
QuiteTimeAfterGest uint32 `protobuf:"varint,7,opt,name=quite_time_after_gest,json=quiteTimeAfterGest,proto3" json:"quite_time_after_gest,omitempty"`
WaitForTimeout uint32 `protobuf:"varint,8,opt,name=wait_for_timeout,json=waitForTimeout,proto3" json:"wait_for_timeout,omitempty"`
AxisSel uint32 `protobuf:"varint,9,opt,name=axis_sel,json=axisSel,proto3" json:"axis_sel,omitempty"`
EnableSingle bool `protobuf:"varint,10,opt,name=enable_single,json=enableSingle,proto3" json:"enable_single,omitempty"`
EnableDouble bool `protobuf:"varint,11,opt,name=enable_double,json=enableDouble,proto3" json:"enable_double,omitempty"`
EnableTriple bool `protobuf:"varint,12,opt,name=enable_triple,json=enableTriple,proto3" json:"enable_triple,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *TapConfigResponse) Reset() {
*x = TapConfigResponse{}
mi := &file_uart_messages_proto_msgTypes[38]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *TapConfigResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TapConfigResponse) ProtoMessage() {}
func (x *TapConfigResponse) ProtoReflect() protoreflect.Message {
mi := &file_uart_messages_proto_msgTypes[38]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TapConfigResponse.ProtoReflect.Descriptor instead.
func (*TapConfigResponse) Descriptor() ([]byte, []int) {
return file_uart_messages_proto_rawDescGZIP(), []int{38}
}
func (x *TapConfigResponse) GetClientId() uint32 {
if x != nil {
return x.ClientId
}
return 0
}
func (x *TapConfigResponse) GetSuccess() bool {
if x != nil {
return x.Success
}
return false
}
func (x *TapConfigResponse) GetSlavesUpdated() uint32 {
if x != nil {
return x.SlavesUpdated
}
return 0
}
func (x *TapConfigResponse) GetTapSensThres() uint32 {
if x != nil {
return x.TapSensThres
}
return 0
}
func (x *TapConfigResponse) GetMaxGestDur() uint32 {
if x != nil {
return x.MaxGestDur
}
return 0
}
func (x *TapConfigResponse) GetTapShockDur() uint32 {
if x != nil {
return x.TapShockDur
}
return 0
}
func (x *TapConfigResponse) GetQuiteTimeAfterGest() uint32 {
if x != nil {
return x.QuiteTimeAfterGest
}
return 0
}
func (x *TapConfigResponse) GetWaitForTimeout() uint32 {
if x != nil {
return x.WaitForTimeout
}
return 0
}
func (x *TapConfigResponse) GetAxisSel() uint32 {
if x != nil {
return x.AxisSel
}
return 0
}
func (x *TapConfigResponse) GetEnableSingle() bool {
if x != nil {
return x.EnableSingle
}
return false
}
func (x *TapConfigResponse) GetEnableDouble() bool {
if x != nil {
return x.EnableDouble
}
return false
}
func (x *TapConfigResponse) GetEnableTriple() bool {
if x != nil {
return x.EnableTriple
}
return false
}
// Host → device: begin UART OTA (erase inactive OTA slot; device replies OTA_STATUS). // Host → device: begin UART OTA (erase inactive OTA slot; device replies OTA_STATUS).
type OtaStartPayload struct { type OtaStartPayload struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
@@ -3061,7 +3363,7 @@ type OtaStartPayload struct {
func (x *OtaStartPayload) Reset() { func (x *OtaStartPayload) Reset() {
*x = OtaStartPayload{} *x = OtaStartPayload{}
mi := &file_uart_messages_proto_msgTypes[37] mi := &file_uart_messages_proto_msgTypes[39]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -3073,7 +3375,7 @@ func (x *OtaStartPayload) String() string {
func (*OtaStartPayload) ProtoMessage() {} func (*OtaStartPayload) ProtoMessage() {}
func (x *OtaStartPayload) ProtoReflect() protoreflect.Message { func (x *OtaStartPayload) ProtoReflect() protoreflect.Message {
mi := &file_uart_messages_proto_msgTypes[37] mi := &file_uart_messages_proto_msgTypes[39]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -3086,7 +3388,7 @@ func (x *OtaStartPayload) ProtoReflect() protoreflect.Message {
// Deprecated: Use OtaStartPayload.ProtoReflect.Descriptor instead. // Deprecated: Use OtaStartPayload.ProtoReflect.Descriptor instead.
func (*OtaStartPayload) Descriptor() ([]byte, []int) { func (*OtaStartPayload) Descriptor() ([]byte, []int) {
return file_uart_messages_proto_rawDescGZIP(), []int{37} return file_uart_messages_proto_rawDescGZIP(), []int{39}
} }
func (x *OtaStartPayload) GetTotalSize() uint32 { func (x *OtaStartPayload) GetTotalSize() uint32 {
@@ -3107,7 +3409,7 @@ type OtaPayload struct {
func (x *OtaPayload) Reset() { func (x *OtaPayload) Reset() {
*x = OtaPayload{} *x = OtaPayload{}
mi := &file_uart_messages_proto_msgTypes[38] mi := &file_uart_messages_proto_msgTypes[40]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -3119,7 +3421,7 @@ func (x *OtaPayload) String() string {
func (*OtaPayload) ProtoMessage() {} func (*OtaPayload) ProtoMessage() {}
func (x *OtaPayload) ProtoReflect() protoreflect.Message { func (x *OtaPayload) ProtoReflect() protoreflect.Message {
mi := &file_uart_messages_proto_msgTypes[38] mi := &file_uart_messages_proto_msgTypes[40]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -3132,7 +3434,7 @@ func (x *OtaPayload) ProtoReflect() protoreflect.Message {
// Deprecated: Use OtaPayload.ProtoReflect.Descriptor instead. // Deprecated: Use OtaPayload.ProtoReflect.Descriptor instead.
func (*OtaPayload) Descriptor() ([]byte, []int) { func (*OtaPayload) Descriptor() ([]byte, []int) {
return file_uart_messages_proto_rawDescGZIP(), []int{38} return file_uart_messages_proto_rawDescGZIP(), []int{40}
} }
func (x *OtaPayload) GetSeq() uint32 { func (x *OtaPayload) GetSeq() uint32 {
@@ -3158,7 +3460,7 @@ type OtaEndPayload struct {
func (x *OtaEndPayload) Reset() { func (x *OtaEndPayload) Reset() {
*x = OtaEndPayload{} *x = OtaEndPayload{}
mi := &file_uart_messages_proto_msgTypes[39] mi := &file_uart_messages_proto_msgTypes[41]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -3170,7 +3472,7 @@ func (x *OtaEndPayload) String() string {
func (*OtaEndPayload) ProtoMessage() {} func (*OtaEndPayload) ProtoMessage() {}
func (x *OtaEndPayload) ProtoReflect() protoreflect.Message { func (x *OtaEndPayload) ProtoReflect() protoreflect.Message {
mi := &file_uart_messages_proto_msgTypes[39] mi := &file_uart_messages_proto_msgTypes[41]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -3183,7 +3485,7 @@ func (x *OtaEndPayload) ProtoReflect() protoreflect.Message {
// Deprecated: Use OtaEndPayload.ProtoReflect.Descriptor instead. // Deprecated: Use OtaEndPayload.ProtoReflect.Descriptor instead.
func (*OtaEndPayload) Descriptor() ([]byte, []int) { func (*OtaEndPayload) Descriptor() ([]byte, []int) {
return file_uart_messages_proto_rawDescGZIP(), []int{39} return file_uart_messages_proto_rawDescGZIP(), []int{41}
} }
// Device → host status (also used as ACK after each 4 KiB written). // Device → host status (also used as ACK after each 4 KiB written).
@@ -3200,7 +3502,7 @@ type OtaStatusPayload struct {
func (x *OtaStatusPayload) Reset() { func (x *OtaStatusPayload) Reset() {
*x = OtaStatusPayload{} *x = OtaStatusPayload{}
mi := &file_uart_messages_proto_msgTypes[40] mi := &file_uart_messages_proto_msgTypes[42]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -3212,7 +3514,7 @@ func (x *OtaStatusPayload) String() string {
func (*OtaStatusPayload) ProtoMessage() {} func (*OtaStatusPayload) ProtoMessage() {}
func (x *OtaStatusPayload) ProtoReflect() protoreflect.Message { func (x *OtaStatusPayload) ProtoReflect() protoreflect.Message {
mi := &file_uart_messages_proto_msgTypes[40] mi := &file_uart_messages_proto_msgTypes[42]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -3225,7 +3527,7 @@ func (x *OtaStatusPayload) ProtoReflect() protoreflect.Message {
// Deprecated: Use OtaStatusPayload.ProtoReflect.Descriptor instead. // Deprecated: Use OtaStatusPayload.ProtoReflect.Descriptor instead.
func (*OtaStatusPayload) Descriptor() ([]byte, []int) { func (*OtaStatusPayload) Descriptor() ([]byte, []int) {
return file_uart_messages_proto_rawDescGZIP(), []int{40} return file_uart_messages_proto_rawDescGZIP(), []int{42}
} }
func (x *OtaStatusPayload) GetStatus() uint32 { func (x *OtaStatusPayload) GetStatus() uint32 {
@@ -3266,7 +3568,7 @@ type OtaSlaveProgressRequest struct {
func (x *OtaSlaveProgressRequest) Reset() { func (x *OtaSlaveProgressRequest) Reset() {
*x = OtaSlaveProgressRequest{} *x = OtaSlaveProgressRequest{}
mi := &file_uart_messages_proto_msgTypes[41] mi := &file_uart_messages_proto_msgTypes[43]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -3278,7 +3580,7 @@ func (x *OtaSlaveProgressRequest) String() string {
func (*OtaSlaveProgressRequest) ProtoMessage() {} func (*OtaSlaveProgressRequest) ProtoMessage() {}
func (x *OtaSlaveProgressRequest) ProtoReflect() protoreflect.Message { func (x *OtaSlaveProgressRequest) ProtoReflect() protoreflect.Message {
mi := &file_uart_messages_proto_msgTypes[41] mi := &file_uart_messages_proto_msgTypes[43]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -3291,7 +3593,7 @@ func (x *OtaSlaveProgressRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use OtaSlaveProgressRequest.ProtoReflect.Descriptor instead. // Deprecated: Use OtaSlaveProgressRequest.ProtoReflect.Descriptor instead.
func (*OtaSlaveProgressRequest) Descriptor() ([]byte, []int) { func (*OtaSlaveProgressRequest) Descriptor() ([]byte, []int) {
return file_uart_messages_proto_rawDescGZIP(), []int{41} return file_uart_messages_proto_rawDescGZIP(), []int{43}
} }
func (x *OtaSlaveProgressRequest) GetClientId() uint32 { func (x *OtaSlaveProgressRequest) GetClientId() uint32 {
@@ -3315,7 +3617,7 @@ type OtaSlaveProgressEntry struct {
func (x *OtaSlaveProgressEntry) Reset() { func (x *OtaSlaveProgressEntry) Reset() {
*x = OtaSlaveProgressEntry{} *x = OtaSlaveProgressEntry{}
mi := &file_uart_messages_proto_msgTypes[42] mi := &file_uart_messages_proto_msgTypes[44]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -3327,7 +3629,7 @@ func (x *OtaSlaveProgressEntry) String() string {
func (*OtaSlaveProgressEntry) ProtoMessage() {} func (*OtaSlaveProgressEntry) ProtoMessage() {}
func (x *OtaSlaveProgressEntry) ProtoReflect() protoreflect.Message { func (x *OtaSlaveProgressEntry) ProtoReflect() protoreflect.Message {
mi := &file_uart_messages_proto_msgTypes[42] mi := &file_uart_messages_proto_msgTypes[44]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -3340,7 +3642,7 @@ func (x *OtaSlaveProgressEntry) ProtoReflect() protoreflect.Message {
// Deprecated: Use OtaSlaveProgressEntry.ProtoReflect.Descriptor instead. // Deprecated: Use OtaSlaveProgressEntry.ProtoReflect.Descriptor instead.
func (*OtaSlaveProgressEntry) Descriptor() ([]byte, []int) { func (*OtaSlaveProgressEntry) Descriptor() ([]byte, []int) {
return file_uart_messages_proto_rawDescGZIP(), []int{42} return file_uart_messages_proto_rawDescGZIP(), []int{44}
} }
func (x *OtaSlaveProgressEntry) GetClientId() uint32 { func (x *OtaSlaveProgressEntry) GetClientId() uint32 {
@@ -3391,7 +3693,7 @@ type OtaSlaveProgressResponse struct {
func (x *OtaSlaveProgressResponse) Reset() { func (x *OtaSlaveProgressResponse) Reset() {
*x = OtaSlaveProgressResponse{} *x = OtaSlaveProgressResponse{}
mi := &file_uart_messages_proto_msgTypes[43] mi := &file_uart_messages_proto_msgTypes[45]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -3403,7 +3705,7 @@ func (x *OtaSlaveProgressResponse) String() string {
func (*OtaSlaveProgressResponse) ProtoMessage() {} func (*OtaSlaveProgressResponse) ProtoMessage() {}
func (x *OtaSlaveProgressResponse) ProtoReflect() protoreflect.Message { func (x *OtaSlaveProgressResponse) ProtoReflect() protoreflect.Message {
mi := &file_uart_messages_proto_msgTypes[43] mi := &file_uart_messages_proto_msgTypes[45]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -3416,7 +3718,7 @@ func (x *OtaSlaveProgressResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use OtaSlaveProgressResponse.ProtoReflect.Descriptor instead. // Deprecated: Use OtaSlaveProgressResponse.ProtoReflect.Descriptor instead.
func (*OtaSlaveProgressResponse) Descriptor() ([]byte, []int) { func (*OtaSlaveProgressResponse) Descriptor() ([]byte, []int) {
return file_uart_messages_proto_rawDescGZIP(), []int{43} return file_uart_messages_proto_rawDescGZIP(), []int{45}
} }
func (x *OtaSlaveProgressResponse) GetActive() bool { func (x *OtaSlaveProgressResponse) GetActive() bool {
@@ -3458,7 +3760,7 @@ var File_uart_messages_proto protoreflect.FileDescriptor
const file_uart_messages_proto_rawDesc = "" + const file_uart_messages_proto_rawDesc = "" +
"\n" + "\n" +
"\x13uart_messages.proto\x12\x04alox\x1a\fnanopb.proto\"\xc0\x14\n" + "\x13uart_messages.proto\x12\x04alox\x1a\fnanopb.proto\"\xd3\x15\n" +
"\vUartMessage\x12%\n" + "\vUartMessage\x12%\n" +
"\x04type\x18\x01 \x01(\x0e2\x11.alox.MessageTypeR\x04type\x12,\n" + "\x04type\x18\x01 \x01(\x0e2\x11.alox.MessageTypeR\x04type\x12,\n" +
"\vack_payload\x18\x02 \x01(\v2\t.alox.AckH\x00R\n" + "\vack_payload\x18\x02 \x01(\v2\t.alox.AckH\x00R\n" +
@@ -3497,7 +3799,9 @@ const file_uart_messages_proto_rawDesc = "" +
"\x18espnow_echo_ping_request\x18# \x01(\v2\x1b.alox.EspNowEchoPingRequestH\x00R\x15espnowEchoPingRequest\x12Y\n" + "\x18espnow_echo_ping_request\x18# \x01(\v2\x1b.alox.EspNowEchoPingRequestH\x00R\x15espnowEchoPingRequest\x12Y\n" +
"\x19espnow_echo_ping_response\x18$ \x01(\v2\x1c.alox.EspNowEchoPingResponseH\x00R\x16espnowEchoPingResponse\x12M\n" + "\x19espnow_echo_ping_response\x18$ \x01(\v2\x1c.alox.EspNowEchoPingResponseH\x00R\x16espnowEchoPingResponse\x12M\n" +
"\x15set_log_level_request\x18% \x01(\v2\x18.alox.SetLogLevelRequestH\x00R\x12setLogLevelRequest\x12P\n" + "\x15set_log_level_request\x18% \x01(\v2\x18.alox.SetLogLevelRequestH\x00R\x12setLogLevelRequest\x12P\n" +
"\x16set_log_level_response\x18& \x01(\v2\x19.alox.SetLogLevelResponseH\x00R\x13setLogLevelResponseB\t\n" + "\x16set_log_level_response\x18& \x01(\v2\x19.alox.SetLogLevelResponseH\x00R\x13setLogLevelResponse\x12F\n" +
"\x12tap_config_request\x18' \x01(\v2\x16.alox.TapConfigRequestH\x00R\x10tapConfigRequest\x12I\n" +
"\x13tap_config_response\x18( \x01(\v2\x17.alox.TapConfigResponseH\x00R\x11tapConfigResponseB\t\n" +
"\apayload\"\x05\n" + "\apayload\"\x05\n" +
"\x03Ack\"!\n" + "\x03Ack\"!\n" +
"\vEchoPayload\x12\x12\n" + "\vEchoPayload\x12\x12\n" +
@@ -3666,7 +3970,38 @@ const file_uart_messages_proto_rawDesc = "" +
"\x05level\x18\x02 \x01(\rR\x05level\"E\n" + "\x05level\x18\x02 \x01(\rR\x05level\"E\n" +
"\x13SetLogLevelResponse\x12\x18\n" + "\x13SetLogLevelResponse\x12\x18\n" +
"\asuccess\x18\x01 \x01(\bR\asuccess\x12\x14\n" + "\asuccess\x18\x01 \x01(\bR\asuccess\x12\x14\n" +
"\x05level\x18\x02 \x01(\rR\x05level\"0\n" + "\x05level\x18\x02 \x01(\rR\x05level\"\xb9\x03\n" +
"\x10TapConfigRequest\x12\x14\n" +
"\x05write\x18\x01 \x01(\bR\x05write\x12\x1b\n" +
"\tclient_id\x18\x02 \x01(\rR\bclientId\x12\x1f\n" +
"\vall_clients\x18\x03 \x01(\bR\n" +
"allClients\x12$\n" +
"\x0etap_sens_thres\x18\x04 \x01(\rR\ftapSensThres\x12 \n" +
"\fmax_gest_dur\x18\x05 \x01(\rR\n" +
"maxGestDur\x12\"\n" +
"\rtap_shock_dur\x18\x06 \x01(\rR\vtapShockDur\x121\n" +
"\x15quite_time_after_gest\x18\a \x01(\rR\x12quiteTimeAfterGest\x12(\n" +
"\x10wait_for_timeout\x18\b \x01(\rR\x0ewaitForTimeout\x12\x19\n" +
"\baxis_sel\x18\t \x01(\rR\aaxisSel\x12#\n" +
"\renable_single\x18\n" +
" \x01(\bR\fenableSingle\x12#\n" +
"\renable_double\x18\v \x01(\bR\fenableDouble\x12#\n" +
"\renable_triple\x18\f \x01(\bR\fenableTriple\"\xc4\x03\n" +
"\x11TapConfigResponse\x12\x1b\n" +
"\tclient_id\x18\x01 \x01(\rR\bclientId\x12\x18\n" +
"\asuccess\x18\x02 \x01(\bR\asuccess\x12%\n" +
"\x0eslaves_updated\x18\x03 \x01(\rR\rslavesUpdated\x12$\n" +
"\x0etap_sens_thres\x18\x04 \x01(\rR\ftapSensThres\x12 \n" +
"\fmax_gest_dur\x18\x05 \x01(\rR\n" +
"maxGestDur\x12\"\n" +
"\rtap_shock_dur\x18\x06 \x01(\rR\vtapShockDur\x121\n" +
"\x15quite_time_after_gest\x18\a \x01(\rR\x12quiteTimeAfterGest\x12(\n" +
"\x10wait_for_timeout\x18\b \x01(\rR\x0ewaitForTimeout\x12\x19\n" +
"\baxis_sel\x18\t \x01(\rR\aaxisSel\x12#\n" +
"\renable_single\x18\n" +
" \x01(\bR\fenableSingle\x12#\n" +
"\renable_double\x18\v \x01(\bR\fenableDouble\x12#\n" +
"\renable_triple\x18\f \x01(\bR\fenableTriple\"0\n" +
"\x0fOtaStartPayload\x12\x1d\n" + "\x0fOtaStartPayload\x12\x1d\n" +
"\n" + "\n" +
"total_size\x18\x01 \x01(\rR\ttotalSize\":\n" + "total_size\x18\x01 \x01(\rR\ttotalSize\":\n" +
@@ -3697,7 +4032,7 @@ const file_uart_messages_proto_rawDesc = "" +
"\x0faggregate_bytes\x18\x03 \x01(\rR\x0eaggregateBytes\x12\x1f\n" + "\x0faggregate_bytes\x18\x03 \x01(\rR\x0eaggregateBytes\x12\x1f\n" +
"\vslave_count\x18\x04 \x01(\rR\n" + "\vslave_count\x18\x04 \x01(\rR\n" +
"slaveCount\x12:\n" + "slaveCount\x12:\n" +
"\x06slaves\x18\x05 \x03(\v2\x1b.alox.OtaSlaveProgressEntryB\x05\x92?\x02\x10\x10R\x06slaves*\x9a\x03\n" + "\x06slaves\x18\x05 \x03(\v2\x1b.alox.OtaSlaveProgressEntryB\x05\x92?\x02\x10\x10R\x06slaves*\xaa\x03\n" +
"\vMessageType\x12\v\n" + "\vMessageType\x12\v\n" +
"\aUNKNOWN\x10\x00\x12\a\n" + "\aUNKNOWN\x10\x00\x12\a\n" +
"\x03ACK\x10\x01\x12\b\n" + "\x03ACK\x10\x01\x12\b\n" +
@@ -3723,7 +4058,9 @@ const file_uart_messages_proto_rawDesc = "" +
"TAP_NOTIFY\x10\x1b\x12\x10\n" + "TAP_NOTIFY\x10\x1b\x12\x10\n" +
"\fCACHE_STATUS\x10\x1d\x12\x14\n" + "\fCACHE_STATUS\x10\x1d\x12\x14\n" +
"\x10ESPNOW_ECHO_PING\x10\x1e\x12\x11\n" + "\x10ESPNOW_ECHO_PING\x10\x1e\x12\x11\n" +
"\rSET_LOG_LEVEL\x10\x1f\"\x04\b\x18\x10\x18\"\x04\b\x1c\x10\x1c*G\n" + "\rSET_LOG_LEVEL\x10\x1f\x12\x0e\n" +
"\n" +
"TAP_CONFIG\x10 \"\x04\b\x18\x10\x18\"\x04\b\x1c\x10\x1c*G\n" +
"\aTapKind\x12\f\n" + "\aTapKind\x12\f\n" +
"\bTAP_NONE\x10\x00\x12\x0e\n" + "\bTAP_NONE\x10\x00\x12\x0e\n" +
"\n" + "\n" +
@@ -3746,7 +4083,7 @@ func file_uart_messages_proto_rawDescGZIP() []byte {
} }
var file_uart_messages_proto_enumTypes = make([]protoimpl.EnumInfo, 2) var file_uart_messages_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
var file_uart_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 44) var file_uart_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 46)
var file_uart_messages_proto_goTypes = []any{ var file_uart_messages_proto_goTypes = []any{
(MessageType)(0), // 0: alox.MessageType (MessageType)(0), // 0: alox.MessageType
(TapKind)(0), // 1: alox.TapKind (TapKind)(0), // 1: alox.TapKind
@@ -3787,13 +4124,15 @@ var file_uart_messages_proto_goTypes = []any{
(*RestartResponse)(nil), // 36: alox.RestartResponse (*RestartResponse)(nil), // 36: alox.RestartResponse
(*SetLogLevelRequest)(nil), // 37: alox.SetLogLevelRequest (*SetLogLevelRequest)(nil), // 37: alox.SetLogLevelRequest
(*SetLogLevelResponse)(nil), // 38: alox.SetLogLevelResponse (*SetLogLevelResponse)(nil), // 38: alox.SetLogLevelResponse
(*OtaStartPayload)(nil), // 39: alox.OtaStartPayload (*TapConfigRequest)(nil), // 39: alox.TapConfigRequest
(*OtaPayload)(nil), // 40: alox.OtaPayload (*TapConfigResponse)(nil), // 40: alox.TapConfigResponse
(*OtaEndPayload)(nil), // 41: alox.OtaEndPayload (*OtaStartPayload)(nil), // 41: alox.OtaStartPayload
(*OtaStatusPayload)(nil), // 42: alox.OtaStatusPayload (*OtaPayload)(nil), // 42: alox.OtaPayload
(*OtaSlaveProgressRequest)(nil), // 43: alox.OtaSlaveProgressRequest (*OtaEndPayload)(nil), // 43: alox.OtaEndPayload
(*OtaSlaveProgressEntry)(nil), // 44: alox.OtaSlaveProgressEntry (*OtaStatusPayload)(nil), // 44: alox.OtaStatusPayload
(*OtaSlaveProgressResponse)(nil), // 45: alox.OtaSlaveProgressResponse (*OtaSlaveProgressRequest)(nil), // 45: alox.OtaSlaveProgressRequest
(*OtaSlaveProgressEntry)(nil), // 46: alox.OtaSlaveProgressEntry
(*OtaSlaveProgressResponse)(nil), // 47: alox.OtaSlaveProgressResponse
} }
var file_uart_messages_proto_depIdxs = []int32{ var file_uart_messages_proto_depIdxs = []int32{
0, // 0: alox.UartMessage.type:type_name -> alox.MessageType 0, // 0: alox.UartMessage.type:type_name -> alox.MessageType
@@ -3802,16 +4141,16 @@ var file_uart_messages_proto_depIdxs = []int32{
5, // 3: alox.UartMessage.version_response:type_name -> alox.VersionResponse 5, // 3: alox.UartMessage.version_response:type_name -> alox.VersionResponse
7, // 4: alox.UartMessage.client_info_response:type_name -> alox.ClientInfoResponse 7, // 4: alox.UartMessage.client_info_response:type_name -> alox.ClientInfoResponse
9, // 5: alox.UartMessage.client_input_response:type_name -> alox.ClientInputResponse 9, // 5: alox.UartMessage.client_input_response:type_name -> alox.ClientInputResponse
39, // 6: alox.UartMessage.ota_start:type_name -> alox.OtaStartPayload 41, // 6: alox.UartMessage.ota_start:type_name -> alox.OtaStartPayload
40, // 7: alox.UartMessage.ota_payload:type_name -> alox.OtaPayload 42, // 7: alox.UartMessage.ota_payload:type_name -> alox.OtaPayload
41, // 8: alox.UartMessage.ota_end:type_name -> alox.OtaEndPayload 43, // 8: alox.UartMessage.ota_end:type_name -> alox.OtaEndPayload
42, // 9: alox.UartMessage.ota_status:type_name -> alox.OtaStatusPayload 44, // 9: alox.UartMessage.ota_status:type_name -> alox.OtaStatusPayload
10, // 10: alox.UartMessage.accel_deadzone_request:type_name -> alox.AccelDeadzoneRequest 10, // 10: alox.UartMessage.accel_deadzone_request:type_name -> alox.AccelDeadzoneRequest
11, // 11: alox.UartMessage.accel_deadzone_response:type_name -> alox.AccelDeadzoneResponse 11, // 11: alox.UartMessage.accel_deadzone_response:type_name -> alox.AccelDeadzoneResponse
27, // 12: alox.UartMessage.espnow_unicast_test_request:type_name -> alox.EspNowUnicastTestRequest 27, // 12: alox.UartMessage.espnow_unicast_test_request:type_name -> alox.EspNowUnicastTestRequest
28, // 13: alox.UartMessage.espnow_unicast_test_response:type_name -> alox.EspNowUnicastTestResponse 28, // 13: alox.UartMessage.espnow_unicast_test_response:type_name -> alox.EspNowUnicastTestResponse
43, // 14: alox.UartMessage.ota_slave_progress_request:type_name -> alox.OtaSlaveProgressRequest 45, // 14: alox.UartMessage.ota_slave_progress_request:type_name -> alox.OtaSlaveProgressRequest
45, // 15: alox.UartMessage.ota_slave_progress_response:type_name -> alox.OtaSlaveProgressResponse 47, // 15: alox.UartMessage.ota_slave_progress_response:type_name -> alox.OtaSlaveProgressResponse
31, // 16: alox.UartMessage.led_ring_progress_request:type_name -> alox.LedRingProgressRequest 31, // 16: alox.UartMessage.led_ring_progress_request:type_name -> alox.LedRingProgressRequest
32, // 17: alox.UartMessage.led_ring_progress_response:type_name -> alox.LedRingProgressResponse 32, // 17: alox.UartMessage.led_ring_progress_response:type_name -> alox.LedRingProgressResponse
33, // 18: alox.UartMessage.espnow_find_me_request:type_name -> alox.EspNowFindMeRequest 33, // 18: alox.UartMessage.espnow_find_me_request:type_name -> alox.EspNowFindMeRequest
@@ -3830,22 +4169,24 @@ var file_uart_messages_proto_depIdxs = []int32{
30, // 31: alox.UartMessage.espnow_echo_ping_response:type_name -> alox.EspNowEchoPingResponse 30, // 31: alox.UartMessage.espnow_echo_ping_response:type_name -> alox.EspNowEchoPingResponse
37, // 32: alox.UartMessage.set_log_level_request:type_name -> alox.SetLogLevelRequest 37, // 32: alox.UartMessage.set_log_level_request:type_name -> alox.SetLogLevelRequest
38, // 33: alox.UartMessage.set_log_level_response:type_name -> alox.SetLogLevelResponse 38, // 33: alox.UartMessage.set_log_level_response:type_name -> alox.SetLogLevelResponse
6, // 34: alox.ClientInfoResponse.clients:type_name -> alox.ClientInfo 39, // 34: alox.UartMessage.tap_config_request:type_name -> alox.TapConfigRequest
8, // 35: alox.ClientInputResponse.clients:type_name -> alox.ClientInput 40, // 35: alox.UartMessage.tap_config_response:type_name -> alox.TapConfigResponse
15, // 36: alox.BatterySample.lipo1:type_name -> alox.LipoReading 6, // 36: alox.ClientInfoResponse.clients:type_name -> alox.ClientInfo
15, // 37: alox.BatterySample.lipo2:type_name -> alox.LipoReading 8, // 37: alox.ClientInputResponse.clients:type_name -> alox.ClientInput
16, // 38: alox.BatteryStatusResponse.samples:type_name -> alox.BatterySample 15, // 38: alox.BatterySample.lipo1:type_name -> alox.LipoReading
1, // 39: alox.TapEvent.kind:type_name -> alox.TapKind 15, // 39: alox.BatterySample.lipo2:type_name -> alox.LipoReading
1, // 40: alox.CacheClientTap.kind:type_name -> alox.TapKind 16, // 40: alox.BatteryStatusResponse.samples:type_name -> alox.BatterySample
23, // 41: alox.CacheClientStatus.accel:type_name -> alox.CacheClientAccel 1, // 41: alox.TapEvent.kind:type_name -> alox.TapKind
24, // 42: alox.CacheClientStatus.tap:type_name -> alox.CacheClientTap 1, // 42: alox.CacheClientTap.kind:type_name -> alox.TapKind
25, // 43: alox.CacheStatusResponse.clients:type_name -> alox.CacheClientStatus 23, // 43: alox.CacheClientStatus.accel:type_name -> alox.CacheClientAccel
44, // 44: alox.OtaSlaveProgressResponse.slaves:type_name -> alox.OtaSlaveProgressEntry 24, // 44: alox.CacheClientStatus.tap:type_name -> alox.CacheClientTap
45, // [45:45] is the sub-list for method output_type 25, // 45: alox.CacheStatusResponse.clients:type_name -> alox.CacheClientStatus
45, // [45:45] is the sub-list for method input_type 46, // 46: alox.OtaSlaveProgressResponse.slaves:type_name -> alox.OtaSlaveProgressEntry
45, // [45:45] is the sub-list for extension type_name 47, // [47:47] is the sub-list for method output_type
45, // [45:45] is the sub-list for extension extendee 47, // [47:47] is the sub-list for method input_type
0, // [0:45] is the sub-list for field type_name 47, // [47:47] is the sub-list for extension type_name
47, // [47:47] is the sub-list for extension extendee
0, // [0:47] is the sub-list for field type_name
} }
func init() { file_uart_messages_proto_init() } func init() { file_uart_messages_proto_init() }
@@ -3887,6 +4228,8 @@ func file_uart_messages_proto_init() {
(*UartMessage_EspnowEchoPingResponse)(nil), (*UartMessage_EspnowEchoPingResponse)(nil),
(*UartMessage_SetLogLevelRequest)(nil), (*UartMessage_SetLogLevelRequest)(nil),
(*UartMessage_SetLogLevelResponse)(nil), (*UartMessage_SetLogLevelResponse)(nil),
(*UartMessage_TapConfigRequest)(nil),
(*UartMessage_TapConfigResponse)(nil),
} }
type x struct{} type x struct{}
out := protoimpl.TypeBuilder{ out := protoimpl.TypeBuilder{
@@ -3894,7 +4237,7 @@ func file_uart_messages_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_uart_messages_proto_rawDesc), len(file_uart_messages_proto_rawDesc)), RawDescriptor: unsafe.Slice(unsafe.StringData(file_uart_messages_proto_rawDesc), len(file_uart_messages_proto_rawDesc)),
NumEnums: 2, NumEnums: 2,
NumMessages: 44, NumMessages: 46,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,
}, },
+191 -2
View File
@@ -291,6 +291,69 @@
Setzen Setzen
</button> </button>
</div> </div>
<h6 class="text-secondary mb-2 mt-3">Tap-Erkennung (BMA456)</h6>
<div class="row g-2 small">
<div class="col-6 col-md-4">
<label class="form-label text-muted mb-0" for="tap-sens">sens (0–15)</label>
<input id="tap-sens" type="number" class="form-control form-control-sm"
min="0" max="15" x-model.number="masterTapCfg.tap_sens_thres"
:disabled="busy || !state.uart_connected">
</div>
<div class="col-6 col-md-4">
<label class="form-label text-muted mb-0" for="tap-max-gest">max_gest (×5ms)</label>
<input id="tap-max-gest" type="number" class="form-control form-control-sm"
min="0" max="65535" x-model.number="masterTapCfg.max_gest_dur"
:disabled="busy || !state.uart_connected">
</div>
<div class="col-6 col-md-4">
<label class="form-label text-muted mb-0" for="tap-shock">shock (×5ms)</label>
<input id="tap-shock" type="number" class="form-control form-control-sm"
min="0" max="65535" x-model.number="masterTapCfg.tap_shock_dur"
:disabled="busy || !state.uart_connected">
</div>
<div class="col-6 col-md-4">
<label class="form-label text-muted mb-0" for="tap-quiet">quiet (×5ms)</label>
<input id="tap-quiet" type="number" class="form-control form-control-sm"
min="0" max="65535" x-model.number="masterTapCfg.quite_time_after_gest"
:disabled="busy || !state.uart_connected">
</div>
<div class="col-6 col-md-4">
<label class="form-label text-muted mb-0" for="tap-wait">wait (0|1)</label>
<input id="tap-wait" type="number" class="form-control form-control-sm"
min="0" max="1" x-model.number="masterTapCfg.wait_for_timeout"
:disabled="busy || !state.uart_connected">
</div>
<div class="col-6 col-md-4">
<label class="form-label text-muted mb-0" for="tap-axis">axis (0=X…2=Z)</label>
<input id="tap-axis" type="number" class="form-control form-control-sm"
min="0" max="2" x-model.number="masterTapCfg.axis_sel"
:disabled="busy || !state.uart_connected">
</div>
</div>
<div class="d-flex flex-wrap gap-3 align-items-center mt-2 small">
<label class="tap-toggle mb-0">
<input type="checkbox" x-model="masterTapCfg.enable_single"
:disabled="busy || !state.uart_connected"> Single
</label>
<label class="tap-toggle mb-0">
<input type="checkbox" x-model="masterTapCfg.enable_double"
:disabled="busy || !state.uart_connected"> Double
</label>
<label class="tap-toggle mb-0">
<input type="checkbox" x-model="masterTapCfg.enable_triple"
:disabled="busy || !state.uart_connected"> Triple
</label>
<button type="button" class="btn btn-outline-secondary btn-sm"
@click="readMasterTapConfig()"
:disabled="busy || !state.uart_connected">
Lesen
</button>
<button type="button" class="btn btn-primary btn-sm"
@click="setMasterTapConfig()"
:disabled="busy || !state.uart_connected">
Setzen
</button>
</div>
<p class="text-muted small mt-2 mb-0" x-show="!state.uart_connected"> <p class="text-muted small mt-2 mb-0" x-show="!state.uart_connected">
UART nicht verbunden — Eingabe gesperrt. UART nicht verbunden — Eingabe gesperrt.
</p> </p>
@@ -313,6 +376,12 @@
:disabled="busy || !state.uart_connected"> :disabled="busy || !state.uart_connected">
Alle Slaves Alle Slaves
</button> </button>
<button type="button" class="btn btn-outline-secondary btn-sm"
@click="setTapConfigAll()"
:disabled="busy || !state.uart_connected"
title="Master-Tap-Config an alle Slaves (ESP-NOW)">
Tap-Cfg alle
</button>
<span class="badge bg-secondary" x-text="(state.clients || []).length + ' registered'"></span> <span class="badge bg-secondary" x-text="(state.clients || []).length + ' registered'"></span>
</div> </div>
</div> </div>
@@ -348,6 +417,7 @@
<th>Ver</th> <th>Ver</th>
<th>Status</th> <th>Status</th>
<th>Deadzone</th> <th>Deadzone</th>
<th>Tap-Cfg</th>
<th>Accel (LSB)</th> <th>Accel (LSB)</th>
<th>Akku</th> <th>Akku</th>
<th>Accel</th> <th>Accel</th>
@@ -358,7 +428,7 @@
</thead> </thead>
<tbody> <tbody>
<template x-if="!(state.clients || []).length"> <template x-if="!(state.clients || []).length">
<tr><td colspan="11" class="text-muted text-center py-4">No clients</td></tr> <tr><td colspan="12" class="text-muted text-center py-4">No clients</td></tr>
</template> </template>
<template x-for="c in (state.clients || [])" :key="c.id + c.mac"> <template x-for="c in (state.clients || [])" :key="c.id + c.mac">
<tr> <tr>
@@ -371,6 +441,15 @@
x-text="c.available ? 'available' : 'inactive'"></span> x-text="c.available ? 'available' : 'inactive'"></span>
</td> </td>
<td x-text="c.deadzone != null ? c.deadzone : '—'"></td> <td x-text="c.deadzone != null ? c.deadzone : '—'"></td>
<td class="small">
<span x-text="formatTapCfg(c.tap_config)" :title="tapCfgTitle(c.tap_config)"></span>
<button type="button" class="btn btn-outline-primary btn-sm ms-1 py-0 px-1"
@click="setTapConfig(c.id, masterTapCfg)"
:disabled="busy || !state.uart_connected || !c.available"
title="Master-Tap-Config an diesen Slave">
Set
</button>
</td>
<td> <td>
<span class="accel" <span class="accel"
:class="accelCellClass(c)" :class="accelCellClass(c)"
@@ -655,7 +734,20 @@
ws: null, ws: null,
wsConnected: false, wsConnected: false,
masterDz: 100, masterDz: 100,
masterDzSeeded: false,
masterLogLevel: 0, masterLogLevel: 0,
masterTapCfg: {
tap_sens_thres: 5,
max_gest_dur: 100,
tap_shock_dur: 6,
quite_time_after_gest: 60,
wait_for_timeout: 0,
axis_sel: 2,
enable_single: true,
enable_double: true,
enable_triple: true
},
masterTapCfgSeeded: false,
allDz: 100, allDz: 100,
allTapSingle: false, allTapSingle: false,
allTapDouble: false, allTapDouble: false,
@@ -719,8 +811,13 @@
this.state = msg; this.state = msg;
this.preserveBatteryInState(prev, this.state); this.preserveBatteryInState(prev, this.state);
this.syncTapDisplay(msg.clients || []); this.syncTapDisplay(msg.clients || []);
if (msg.master?.deadzone != null) { if (!this.masterDzSeeded && msg.master?.deadzone != null) {
this.masterDz = msg.master.deadzone; this.masterDz = msg.master.deadzone;
this.masterDzSeeded = true;
}
if (!this.masterTapCfgSeeded && msg.master?.tap_config) {
this.applyMasterTapCfg(msg.master.tap_config);
this.masterTapCfgSeeded = true;
} }
for (const c of (msg.clients || [])) { for (const c of (msg.clients || [])) {
if (c.deadzone != null && this.slaveDz[c.id] == null) { if (c.deadzone != null && this.slaveDz[c.id] == null) {
@@ -1124,6 +1221,10 @@
this.flash(`Slaves: Deadzone ${data.deadzone} LSB (${data.slaves_updated} per ESP-NOW, Master unverändert)`, true); this.flash(`Slaves: Deadzone ${data.deadzone} LSB (${data.slaves_updated} per ESP-NOW, Master unverändert)`, true);
return; return;
} }
if (clientId === 0) {
this.masterDz = data.deadzone;
this.masterDzSeeded = true;
}
const who = clientId === 0 ? 'Master' : `Slave ${clientId}`; const who = clientId === 0 ? 'Master' : `Slave ${clientId}`;
this.flash(`${who}: Deadzone ${data.deadzone} LSB gesetzt`, true); this.flash(`${who}: Deadzone ${data.deadzone} LSB gesetzt`, true);
} catch (e) { } catch (e) {
@@ -1142,6 +1243,7 @@
return; return;
} }
this.masterDz = data.deadzone; this.masterDz = data.deadzone;
this.masterDzSeeded = true;
this.flash(`Master: Deadzone ${data.deadzone} LSB`, true); this.flash(`Master: Deadzone ${data.deadzone} LSB`, true);
} catch (e) { } catch (e) {
this.flash(String(e), false); this.flash(String(e), false);
@@ -1152,6 +1254,93 @@
async setMasterDeadzone() { async setMasterDeadzone() {
await this.setDeadzone(0, this.masterDz); await this.setDeadzone(0, this.masterDz);
}, },
formatTapCfg(tc) {
if (!tc) return '—';
return `s${tc.tap_sens_thres}`;
},
tapCfgTitle(tc) {
if (!tc) return '';
const kinds = [tc.enable_single && 'S', tc.enable_double && 'D', tc.enable_triple && 'T'].filter(Boolean).join('/');
return `sens=${tc.tap_sens_thres} max_gest=${tc.max_gest_dur} shock=${tc.tap_shock_dur} quiet=${tc.quite_time_after_gest} wait=${tc.wait_for_timeout} axis=${tc.axis_sel} (${kinds || 'aus'})`;
},
applyMasterTapCfg(data) {
if (!data) return;
this.masterTapCfg = {
tap_sens_thres: data.tap_sens_thres,
max_gest_dur: data.max_gest_dur,
tap_shock_dur: data.tap_shock_dur,
quite_time_after_gest: data.quite_time_after_gest,
wait_for_timeout: data.wait_for_timeout,
axis_sel: data.axis_sel,
enable_single: data.enable_single,
enable_double: data.enable_double,
enable_triple: data.enable_triple
};
this.masterTapCfgSeeded = true;
},
async setTapConfig(clientId, cfg, opts = {}) {
if (!cfg) {
this.flash('Keine Tap-Config', false);
return;
}
this.busy = true;
try {
const r = await fetch('/api/tap-config', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
write: true,
client_id: clientId,
all_clients: !!opts.allClients,
slaves_only: !!opts.slavesOnly,
...cfg
})
});
const data = await r.json();
if (!r.ok || !data.success) {
const err = data.error ||
(opts.slavesOnly ? 'Tap-Config für Slaves fehlgeschlagen' : `Tap-Config für Client ${clientId} fehlgeschlagen`);
this.flash(err, false);
return;
}
if (opts.slavesOnly) {
this.flash(`Slaves: Tap-Config gesetzt (${data.slaves_updated} per ESP-NOW, Master unverändert)`, true);
return;
}
const who = clientId === 0 ? 'Master' : `Slave ${clientId}`;
this.flash(`${who}: Tap-Config gesetzt (sens=${data.tap_sens_thres})`, true);
if (clientId === 0) {
this.applyMasterTapCfg(data);
}
} catch (e) {
this.flash(String(e), false);
} finally {
this.busy = false;
}
},
async readMasterTapConfig() {
this.busy = true;
try {
const r = await fetch('/api/tap-config?client_id=0');
const data = await r.json();
if (!r.ok || !data.success) {
this.flash(data.error || 'Master-Tap-Config lesen fehlgeschlagen', false);
return;
}
this.applyMasterTapCfg(data);
this.flash(`Master: Tap-Config gelesen (sens=${data.tap_sens_thres})`, true);
} catch (e) {
this.flash(String(e), false);
} finally {
this.busy = false;
}
},
async setMasterTapConfig() {
await this.setTapConfig(0, this.masterTapCfg);
},
async setTapConfigAll() {
await this.setTapConfig(0, this.masterTapCfg, { allClients: true, slavesOnly: true });
},
async readMasterLogLevel() { async readMasterLogLevel() {
this.busy = true; this.busy = true;
try { try {
+1
View File
@@ -20,6 +20,7 @@ idf_component_register(
"cmd/cmd_accel_deadzone.c" "cmd/cmd_accel_deadzone.c"
"cmd/cmd_accel_stream.c" "cmd/cmd_accel_stream.c"
"cmd/cmd_tap_notify.c" "cmd/cmd_tap_notify.c"
"cmd/cmd_tap_config.c"
"cmd/cmd_cache_status.c" "cmd/cmd_cache_status.c"
"cmd/cmd_espnow_unicast_test.c" "cmd/cmd_espnow_unicast_test.c"
"cmd/cmd_espnow_echo_ping.c" "cmd/cmd_espnow_echo_ping.c"
+29 -1
View File
@@ -88,12 +88,16 @@ Powerpod uses the Bosch **BMA456H** (hearable) variant, not the generic `bma456w
**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). **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).
Tap detection parameters (`bma456_tap_config_t`) use the same pattern with NVS key `tap_cfg` (blob), UART `TAP_CONFIG`, and ESP-NOW `ESPNOW_SET_TAP_CONFIG`.
**Configuration paths:** **Configuration paths:**
| Path | Effect | | Path | Effect |
|------|--------| |------|--------|
| UART `ACCEL_DEADZONE` with `client_id = 0` | Set + save local deadzone | | UART `ACCEL_DEADZONE` with `client_id = 0` | Set + save local deadzone |
| ESP-NOW `SET_ACCEL_DEADZONE` | Set + save on the receiving slave | | ESP-NOW `SET_ACCEL_DEADZONE` | Set + save on the receiving slave |
| UART `TAP_CONFIG` with `client_id = 0` | Set + save local tap config |
| ESP-NOW `SET_TAP_CONFIG` | Set + save tap config 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.
@@ -116,6 +120,7 @@ Schema: `proto/esp_now_messages.proto`. Encode/decode: `esp_now_proto.c`. The ES
| `ESPNOW_SLAVE_INFO` | Slave → master | `EspNowSlavePresence` | | `ESPNOW_SLAVE_INFO` | Slave → master | `EspNowSlavePresence` |
| `ESPNOW_HEARTBEAT` | Slave → master | `EspNowSlavePresence` (same fields) | | `ESPNOW_HEARTBEAT` | Slave → master | `EspNowSlavePresence` (same fields) |
| `ESPNOW_SET_ACCEL_DEADZONE` | Master → slave | `EspNowAccelDeadzone` (`deadzone` LSB) | | `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_UNICAST_TEST` | Master → slave | `EspNowUnicastTest` (`seq`) | | `ESPNOW_UNICAST_TEST` | Master → slave | `EspNowUnicastTest` (`seq`) |
| `ESPNOW_FIND_ME` | Master → slave | `EspNowFindMe` (`client_id` filter) — LED locate sequence | | `ESPNOW_FIND_ME` | Master → slave | `EspNowFindMe` (`client_id` filter) — LED locate sequence |
| `ESPNOW_RESTART` | Master → slave | `EspNowRestart` (`client_id` filter) — reboot slave | | `ESPNOW_RESTART` | Master → slave | `EspNowRestart` (`client_id` filter) — reboot slave |
@@ -232,6 +237,7 @@ Host and master speak nanopb-encoded `UartMessage` inside UART frames (byte 0 =
| 29 | `CACHE_STATUS` | Implemented (`cmd/cmd_cache_status.c`) — subscribed accel + tap cache (one UART round-trip) | | 29 | `CACHE_STATUS` | Implemented (`cmd/cmd_cache_status.c`) — subscribed accel + tap cache (one UART round-trip) |
| 30 | `ESPNOW_ECHO_PING` | Implemented (`cmd/cmd_espnow_echo_ping.c`) — ESP-NOW timestamp echo (latency test) | | 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 | | 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) |
Regenerate C code: Regenerate C code:
@@ -325,6 +331,27 @@ Sets the **software** deadzone used by `bosch456.c` when logging accel (see [BMA
**Response:** `accel_deadzone_response` with applied `deadzone`, `success`, and `slaves_updated` (ESP-NOW count). **Response:** `accel_deadzone_response` with applied `deadzone`, `success`, and `slaves_updated` (ESP-NOW count).
### TAP_CONFIG command
Get/set **hardware** BMA456H multitap parameters (`tap_sens_thres`, timing fields, `axis_sel`, enable single/double/triple). Applied via `bma456_set_tap_config()` and persisted in NVS (`tap_cfg`) on each target node.
**Request:** framed `20` (`0x20`) + `tap_config_request`:
| Field | Meaning |
|-------|---------|
| `write` | `false` = read, `true` = write |
| `tap_sens_thres` … `enable_triple` | Same fields as `bma456_tap_config_t` |
| `client_id` | `0` = local sensor; `>0` = slave id (master) |
| `all_clients` | Master: ESP-NOW unicast to every registered slave |
**Response:** `tap_config_response` with fields echo, `success`, `slaves_updated`.
```bash
go run . -port /dev/ttyUSB0 tap-config
go run . -port /dev/ttyUSB0 tap-config -set -sens 5 -axis 2
go run . -port /dev/ttyUSB0 tap-config -client 16 -set -sens 7
```
### TAP_NOTIFY command ### TAP_NOTIFY command
Configure which BMA456 tap kinds a **slave** forwards to the master over ESP-NOW. The slave only sends `ESPNOW_TAP_EVENT` when the matching notify flag is enabled (set locally on the slave via ESP-NOW). Configure which BMA456 tap kinds a **slave** forwards to the master over ESP-NOW. The slave only sends `ESPNOW_TAP_EVENT` when the matching notify flag is enabled (set locally on the slave via ESP-NOW).
@@ -578,10 +605,11 @@ 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, on-demand read, tap INT, deadzone filter | | `bosch456.c/h` | BMA456H I2C driver, accel poll, on-demand read, tap INT, deadzone filter |
| `cmd/cmd_tap_notify.c` | UART `TAP_NOTIFY` — ESP-NOW tap notify config | | `cmd/cmd_tap_notify.c` | UART `TAP_NOTIFY` — ESP-NOW tap notify config |
| `cmd/cmd_tap_config.c` | UART `TAP_CONFIG` — BMA456 multitap params + NVS |
| `cmd/cmd_cache_status.c` | UART `CACHE_STATUS` — subscribed accel + tap cache poll | | `cmd/cmd_cache_status.c` | UART `CACHE_STATUS` — subscribed accel + tap cache poll |
| `board_input.c/h` | Taster GPIO12, LiPo ADC on GPIO1 / GPIO11 | | `board_input.c/h` | Taster GPIO12, LiPo ADC on GPIO1 / GPIO11 |
| `battery_uv.c/h` | Software LiPo UV latch, energy-save boot (`POWERPOD_BATTERY_UV_ENABLE`) | | `battery_uv.c/h` | Software LiPo UV latch, energy-save boot (`POWERPOD_BATTERY_UV_ENABLE`) |
| `pod_settings.c/h` | NVS persistence (accel deadzone, UV latch, …) | | `pod_settings.c/h` | NVS persistence (accel deadzone, tap config, UV latch) |
| `led_ring.c/h` | LED ring (digit display, progress bar) | | `led_ring.c/h` | LED ring (digit display, progress bar) |
| `cmd/cmd_led_ring.c` | UART `LED_RING` progress command | | `cmd/cmd_led_ring.c` | UART `LED_RING` progress command |
| `cmd/cmd_set_log_level.c` | UART `SET_LOG_LEVEL` — runtime ESP-IDF log level | | `cmd/cmd_set_log_level.c` | UART `SET_LOG_LEVEL` — runtime ESP-IDF log level |
+92 -45
View File
@@ -38,7 +38,7 @@ static volatile bool s_int_pending;
static SemaphoreHandle_t s_accel_mutex; static SemaphoreHandle_t s_accel_mutex;
static bma456_tap_handler_t s_tap_handler; static bma456_tap_handler_t s_tap_handler;
static void *s_tap_handler_ctx; static void *s_tap_handler_ctx;
static const bma456_tap_config_t s_tap_config = BMA456_TAP_CONFIG_DEFAULT; static bma456_tap_config_t s_tap_config = BMA456_TAP_CONFIG_DEFAULT;
static esp_err_t check_bma4(const char *api_name, int8_t rslt); static esp_err_t check_bma4(const char *api_name, int8_t rslt);
@@ -126,6 +126,96 @@ void bma456_set_accel_deadzone(uint32_t deadzone_lsb) {
uint32_t bma456_get_accel_deadzone(void) { return s_accel_deadzone; } uint32_t bma456_get_accel_deadzone(void) { return s_accel_deadzone; }
bool bma456_tap_config_valid(const bma456_tap_config_t *cfg) {
if (cfg == NULL) {
return false;
}
if (cfg->tap_sens_thres > 15u) {
return false;
}
if (cfg->axis_sel > 2u) {
return false;
}
if (cfg->wait_for_timeout > 1u) {
return false;
}
if (!cfg->enable_single && !cfg->enable_double && !cfg->enable_triple) {
return false;
}
return true;
}
void bma456_get_tap_config(bma456_tap_config_t *cfg_out) {
if (cfg_out == NULL) {
return;
}
*cfg_out = s_tap_config;
}
static esp_err_t apply_tap_parameters(const bma456_tap_config_t *cfg) {
struct bma456h_multitap_settings tap_settings = {0};
int8_t ret = bma456h_tap_get_parameter(&tap_settings, &s_bma456);
if (check_bma4("bma456h_tap_get_parameter", ret) != ESP_OK) {
return ESP_FAIL;
}
tap_settings.tap_sens_thres = cfg->tap_sens_thres;
tap_settings.max_gest_dur = cfg->max_gest_dur;
tap_settings.tap_shock_dur = cfg->tap_shock_dur;
tap_settings.quite_time_after_gest = cfg->quite_time_after_gest;
tap_settings.wait_for_timeout = cfg->wait_for_timeout;
tap_settings.axis_sel = cfg->axis_sel;
ret = bma456h_tap_set_parameter(&tap_settings, &s_bma456);
if (check_bma4("bma456h_tap_set_parameter", ret) != ESP_OK) {
return ESP_FAIL;
}
/* Disable all tap kinds first, then enable the requested set. */
uint16_t all_taps =
BMA456H_SINGLE_TAP_EN | BMA456H_DOUBLE_TAP_EN | BMA456H_TRIPLE_TAP_EN;
ret = bma456h_feature_enable(all_taps, BMA4_DISABLE, &s_bma456);
if (check_bma4("bma456h_feature_enable(disable taps)", ret) != ESP_OK) {
return ESP_FAIL;
}
uint16_t tap_features = 0;
if (cfg->enable_single) {
tap_features |= BMA456H_SINGLE_TAP_EN;
}
if (cfg->enable_double) {
tap_features |= BMA456H_DOUBLE_TAP_EN;
}
if (cfg->enable_triple) {
tap_features |= BMA456H_TRIPLE_TAP_EN;
}
ret = bma456h_feature_enable(tap_features, BMA4_ENABLE, &s_bma456);
if (check_bma4("bma456h_feature_enable(taps)", ret) != ESP_OK) {
return ESP_FAIL;
}
ESP_LOGI(TAG,
"tap config sens=%u max_gest=%u shock=%u quiet=%u wait=%u axis=%u "
"(single=%d double=%d triple=%d)",
(unsigned)cfg->tap_sens_thres, (unsigned)cfg->max_gest_dur,
(unsigned)cfg->tap_shock_dur, (unsigned)cfg->quite_time_after_gest,
(unsigned)cfg->wait_for_timeout, (unsigned)cfg->axis_sel,
cfg->enable_single, cfg->enable_double, cfg->enable_triple);
return ESP_OK;
}
esp_err_t bma456_set_tap_config(const bma456_tap_config_t *cfg) {
if (!bma456_tap_config_valid(cfg)) {
return ESP_ERR_INVALID_ARG;
}
if (s_bma456_ready) {
esp_err_t err = apply_tap_parameters(cfg);
if (err != ESP_OK) {
return err;
}
}
s_tap_config = *cfg;
return ESP_OK;
}
void bma456_set_tap_handler(bma456_tap_handler_t handler, void *ctx) { void bma456_set_tap_handler(bma456_tap_handler_t handler, void *ctx) {
s_tap_handler = handler; s_tap_handler = handler;
s_tap_handler_ctx = ctx; s_tap_handler_ctx = ctx;
@@ -259,52 +349,9 @@ static esp_err_t configure_tap_interrupt(void) {
int8_t ret; int8_t ret;
const uint8_t int_line = BMA4_INTR2_MAP; const uint8_t int_line = BMA4_INTR2_MAP;
struct bma456h_multitap_settings tap_settings = {0}; if (apply_tap_parameters(&s_tap_config) != ESP_OK) {
ret = bma456h_tap_get_parameter(&tap_settings, &s_bma456);
if (check_bma4("bma456h_tap_get_parameter", ret) != ESP_OK) {
return ESP_FAIL; return ESP_FAIL;
} }
tap_settings.tap_sens_thres = s_tap_config.tap_sens_thres;
tap_settings.max_gest_dur = s_tap_config.max_gest_dur;
tap_settings.tap_shock_dur = s_tap_config.tap_shock_dur;
tap_settings.quite_time_after_gest = s_tap_config.quite_time_after_gest;
tap_settings.wait_for_timeout = s_tap_config.wait_for_timeout;
tap_settings.axis_sel = s_tap_config.axis_sel;
ret = bma456h_tap_set_parameter(&tap_settings, &s_bma456);
if (check_bma4("bma456h_tap_set_parameter", ret) != ESP_OK) {
return ESP_FAIL;
}
uint16_t tap_features = 0;
if (s_tap_config.enable_single) {
tap_features |= BMA456H_SINGLE_TAP_EN;
}
if (s_tap_config.enable_double) {
tap_features |= BMA456H_DOUBLE_TAP_EN;
}
if (s_tap_config.enable_triple) {
tap_features |= BMA456H_TRIPLE_TAP_EN;
}
if (tap_features == 0) {
ESP_LOGW(TAG, "tap config: no tap kinds enabled");
return ESP_ERR_INVALID_ARG;
}
ret = bma456h_feature_enable(tap_features, BMA4_ENABLE, &s_bma456);
if (check_bma4("bma456h_feature_enable", ret) != ESP_OK) {
return ESP_FAIL;
}
ESP_LOGI(TAG,
"tap config sens=%u max_gest=%u shock=%u quiet=%u wait=%u axis=%u "
"(single=%d double=%d triple=%d)",
(unsigned)s_tap_config.tap_sens_thres,
(unsigned)s_tap_config.max_gest_dur,
(unsigned)s_tap_config.tap_shock_dur,
(unsigned)s_tap_config.quite_time_after_gest,
(unsigned)s_tap_config.wait_for_timeout,
(unsigned)s_tap_config.axis_sel, s_tap_config.enable_single,
s_tap_config.enable_double, s_tap_config.enable_triple);
ret = bma456h_map_interrupt(int_line, BMA456H_TAP_OUT_INT, BMA4_ENABLE, ret = bma456h_map_interrupt(int_line, BMA456H_TAP_OUT_INT, BMA4_ENABLE,
&s_bma456); &s_bma456);
+14 -1
View File
@@ -42,7 +42,7 @@ typedef struct {
bool enable_triple; bool enable_triple;
} bma456_tap_config_t; } bma456_tap_config_t;
/** Edit these values to tune tap detection, then rebuild. */ /** Edit these values for the compile-time default (overridden by NVS if set). */
#define BMA456_TAP_CONFIG_DEFAULT \ #define BMA456_TAP_CONFIG_DEFAULT \
{ \ { \
.tap_sens_thres = 5, /* sensitive; 0=max, Bosch default=9 */ \ .tap_sens_thres = 5, /* sensitive; 0=max, Bosch default=9 */ \
@@ -56,6 +56,19 @@ typedef struct {
.enable_triple = true, \ .enable_triple = true, \
} }
/** True if cfg fields are within sensor limits and at least one tap kind is on. */
bool bma456_tap_config_valid(const bma456_tap_config_t *cfg);
/** Copy current runtime tap config (compile default until set/NVS-applied). */
void bma456_get_tap_config(bma456_tap_config_t *cfg_out);
/**
* Apply tap config to the sensor (and keep RAM copy).
* Returns ESP_ERR_INVALID_ARG if invalid. When the sensor is not ready, only
* the RAM copy is updated (ESP_OK).
*/
esp_err_t bma456_set_tap_config(const bma456_tap_config_t *cfg);
/** /**
* Probe and configure the sensor on bus_handle (100 kHz device). * Probe and configure the sensor on bus_handle (100 kHz device).
* On failure the device is removed and ESP_ERR_NOT_FOUND / ESP_FAIL is returned; * On failure the device is removed and ESP_ERR_NOT_FOUND / ESP_FAIL is returned;
+54
View File
@@ -82,6 +82,10 @@ static client_slot_t *alloc_slot(const uint8_t mac[CLIENT_MAC_LEN],
slot->active = true; slot->active = true;
memcpy(slot->info.mac, mac, CLIENT_MAC_LEN); memcpy(slot->info.mac, mac, CLIENT_MAC_LEN);
slot->info.accel_deadzone = CLIENT_REGISTRY_DEFAULT_ACCEL_DEADZONE; slot->info.accel_deadzone = CLIENT_REGISTRY_DEFAULT_ACCEL_DEADZONE;
{
static const bma456_tap_config_t k_tap_default = BMA456_TAP_CONFIG_DEFAULT;
slot->info.tap_config = k_tap_default;
}
if (out_is_new != NULL) { if (out_is_new != NULL) {
*out_is_new = true; *out_is_new = true;
} }
@@ -246,6 +250,56 @@ size_t client_registry_set_accel_deadzone_all(uint32_t deadzone) {
return n; return n;
} }
esp_err_t client_registry_set_tap_config(uint32_t client_id,
const bma456_tap_config_t *cfg) {
if (cfg == NULL || !bma456_tap_config_valid(cfg)) {
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;
}
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.tap_config = *cfg;
return ESP_OK;
}
}
return ESP_ERR_NOT_FOUND;
}
esp_err_t client_registry_get_tap_config(uint32_t client_id,
bma456_tap_config_t *cfg_out) {
if (cfg_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;
}
*cfg_out = info->tap_config;
return ESP_OK;
}
size_t client_registry_set_tap_config_all(const bma456_tap_config_t *cfg) {
if (cfg == NULL || !bma456_tap_config_valid(cfg)) {
return 0;
}
size_t n = 0;
for (size_t i = 0; i < CLIENT_REGISTRY_MAX; i++) {
if (!s_clients[i].active) {
continue;
}
s_clients[i].info.tap_config = *cfg;
n++;
}
return n;
}
static void clear_client_accel(client_slot_t *slot) { static void clear_client_accel(client_slot_t *slot) {
if (slot == NULL) { if (slot == NULL) {
return; return;
+9
View File
@@ -2,6 +2,7 @@
#define CLIENT_REGISTRY_H #define CLIENT_REGISTRY_H
#include "board_input.h" #include "board_input.h"
#include "bosch456.h"
#include "esp_err.h" #include "esp_err.h"
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
@@ -22,6 +23,8 @@ typedef struct {
uint32_t version; uint32_t version;
/** Accel deadzone in raw LSB per axis (master copy for ESP-NOW config). */ /** Accel deadzone in raw LSB per axis (master copy for ESP-NOW config). */
uint32_t accel_deadzone; uint32_t accel_deadzone;
/** Tap detection config (master copy for ESP-NOW / UART read). */
bma456_tap_config_t tap_config;
/** Latest accel from slave ESP-NOW stream (master only). */ /** Latest accel from slave ESP-NOW stream (master only). */
bool accel_valid; bool accel_valid;
int16_t accel_x; int16_t accel_x;
@@ -88,6 +91,12 @@ esp_err_t client_registry_get_accel_deadzone(uint32_t client_id,
/** Push deadzone to all active registry entries; returns count updated. */ /** Push deadzone to all active registry entries; returns count updated. */
size_t client_registry_set_accel_deadzone_all(uint32_t deadzone); size_t client_registry_set_accel_deadzone_all(uint32_t deadzone);
esp_err_t client_registry_set_tap_config(uint32_t client_id,
const bma456_tap_config_t *cfg);
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);
/** Store latest accel sample from a slave (matched by sender MAC). */ /** 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], esp_err_t client_registry_update_accel(const uint8_t mac[CLIENT_MAC_LEN],
uint32_t slave_id, int16_t x, int16_t y, uint32_t slave_id, int16_t x, int16_t y,
+2
View File
@@ -61,6 +61,8 @@ static const char *message_type_name(uint16_t id) {
return "ESPNOW_ECHO_PING"; return "ESPNOW_ECHO_PING";
case alox_MessageType_SET_LOG_LEVEL: case alox_MessageType_SET_LOG_LEVEL:
return "SET_LOG_LEVEL"; return "SET_LOG_LEVEL";
case alox_MessageType_TAP_CONFIG:
return "TAP_CONFIG";
default: default:
return "UNKNOWN"; return "UNKNOWN";
} }
+162
View File
@@ -0,0 +1,162 @@
#include "bosch456.h"
#include "client_registry.h"
#include "cmd_tap_config.h"
#include "esp_log.h"
#include "esp_now_comm.h"
#include "pod_settings.h"
#include "uart_cmd.h"
static const char *TAG = "[TAP_CFG]";
static void fill_response_fields(alox_TapConfigResponse *out,
const bma456_tap_config_t *cfg) {
out->tap_sens_thres = cfg->tap_sens_thres;
out->max_gest_dur = cfg->max_gest_dur;
out->tap_shock_dur = cfg->tap_shock_dur;
out->quite_time_after_gest = cfg->quite_time_after_gest;
out->wait_for_timeout = cfg->wait_for_timeout;
out->axis_sel = cfg->axis_sel;
out->enable_single = cfg->enable_single;
out->enable_double = cfg->enable_double;
out->enable_triple = cfg->enable_triple;
}
static void reply(uint32_t client_id, bool success, uint32_t slaves_updated,
const bma456_tap_config_t *cfg) {
alox_UartMessage response;
uart_cmd_init_response(&response, alox_MessageType_TAP_CONFIG,
alox_UartMessage_tap_config_response_tag);
response.payload.tap_config_response.client_id = client_id;
response.payload.tap_config_response.success = success;
response.payload.tap_config_response.slaves_updated = slaves_updated;
if (cfg != NULL) {
fill_response_fields(&response.payload.tap_config_response, cfg);
}
uart_cmd_send(&response, TAG);
}
static void req_to_cfg(const alox_TapConfigRequest *req,
bma456_tap_config_t *cfg) {
cfg->tap_sens_thres = (uint16_t)req->tap_sens_thres;
cfg->max_gest_dur = (uint16_t)req->max_gest_dur;
cfg->tap_shock_dur = (uint16_t)req->tap_shock_dur;
cfg->quite_time_after_gest = (uint16_t)req->quite_time_after_gest;
cfg->wait_for_timeout = (uint16_t)req->wait_for_timeout;
cfg->axis_sel = (uint16_t)req->axis_sel;
cfg->enable_single = req->enable_single;
cfg->enable_double = req->enable_double;
cfg->enable_triple = req->enable_triple;
}
static void apply_local_tap_config(const bma456_tap_config_t *cfg) {
if (bma456_set_tap_config(cfg) != ESP_OK) {
ESP_LOGW(TAG, "local tap config apply failed");
return;
}
if (pod_settings_save_tap_config(cfg) != ESP_OK) {
ESP_LOGW(TAG, "tap config applied but not saved to NVS");
}
}
static esp_err_t push_tap_config_to_slave(const client_info_t *client,
const bma456_tap_config_t *cfg) {
if (client == NULL || cfg == NULL) {
return ESP_ERR_INVALID_ARG;
}
esp_err_t err = client_registry_set_tap_config(client->id, cfg);
if (err != ESP_OK) {
return err;
}
return esp_now_comm_send_tap_config(client->mac, client->id, cfg);
}
static void handle_tap_config(const uint8_t *data, size_t len) {
alox_UartMessage uart_msg;
alox_TapConfigRequest req = alox_TapConfigRequest_init_zero;
static const bma456_tap_config_t k_default = BMA456_TAP_CONFIG_DEFAULT;
if (uart_cmd_decode(data, len, &uart_msg) != ESP_OK) {
ESP_LOGW(TAG, "decode failed");
reply(0, false, 0, &k_default);
return;
}
const alox_TapConfigRequest *req_ptr =
UART_CMD_REQ(&uart_msg, alox_UartMessage_tap_config_request_tag,
tap_config_request);
if (req_ptr != NULL) {
req = *req_ptr;
}
bma456_tap_config_t cfg;
req_to_cfg(&req, &cfg);
if (req.write) {
if (!bma456_tap_config_valid(&cfg)) {
ESP_LOGW(TAG, "invalid tap config");
reply(req.client_id, false, 0, &cfg);
return;
}
if (req.all_clients) {
size_t n = client_registry_set_tap_config_all(&cfg);
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_tap_config(client->mac, client->id, &cfg) ==
ESP_OK) {
sent++;
}
}
if (bma456_is_ready()) {
apply_local_tap_config(&cfg);
}
ESP_LOGI(TAG, "set tap config via unicast to %u/%u slaves",
(unsigned)sent, (unsigned)n);
reply(0, sent > 0 || bma456_is_ready(), sent, &cfg);
return;
}
if (req.client_id == 0) {
apply_local_tap_config(&cfg);
ESP_LOGI(TAG, "set local tap config (no ESP-NOW; use -client or -all "
"for slaves)");
reply(0, true, 0, &cfg);
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, 0, &cfg);
return;
}
esp_err_t err = push_tap_config_to_slave(client, &cfg);
reply(req.client_id, err == ESP_OK, err == ESP_OK ? 1 : 0, &cfg);
return;
}
if (req.all_clients || req.client_id == 0) {
bma456_tap_config_t local;
bma456_get_tap_config(&local);
reply(0, true, 0, &local);
return;
}
bma456_tap_config_t cached;
esp_err_t err = client_registry_get_tap_config(req.client_id, &cached);
reply(req.client_id, err == ESP_OK, 0, err == ESP_OK ? &cached : &k_default);
}
void cmd_tap_config_register(void) {
uart_cmd_register(alox_MessageType_TAP_CONFIG, handle_tap_config);
}
+6
View File
@@ -0,0 +1,6 @@
#ifndef CMD_TAP_CONFIG_H
#define CMD_TAP_CONFIG_H
void cmd_tap_config_register(void);
#endif
+5
View File
@@ -22,6 +22,11 @@ esp_err_t esp_now_comm_send_tap_notify(const uint8_t mac[CLIENT_MAC_LEN],
esp_err_t esp_now_comm_send_accel_deadzone(const uint8_t mac[CLIENT_MAC_LEN], esp_err_t esp_now_comm_send_accel_deadzone(const uint8_t mac[CLIENT_MAC_LEN],
uint32_t client_id, uint32_t deadzone); uint32_t client_id, uint32_t deadzone);
/** Master: unicast BMA456 tap config to one slave. */
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: send minimal unicast test payload to verify master→slave path. */ /** 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], esp_err_t esp_now_comm_send_unicast_test(const uint8_t mac[CLIENT_MAC_LEN],
uint32_t seq); uint32_t seq);
+40
View File
@@ -45,6 +45,24 @@ static esp_err_t send_accel_deadzone(const uint8_t *dest_mac, uint32_t client_id
return esp_now_core_send(dest_mac, &msg); return esp_now_core_send(dest_mac, &msg);
} }
static esp_err_t send_tap_config(const uint8_t *dest_mac, uint32_t client_id,
const bma456_tap_config_t *cfg) {
alox_EspNowMessage msg = alox_EspNowMessage_init_zero;
msg.type = alox_EspNowMessageType_ESPNOW_SET_TAP_CONFIG;
msg.which_payload = alox_EspNowMessage_tap_config_tag;
msg.payload.tap_config.client_id = client_id;
msg.payload.tap_config.tap_sens_thres = cfg->tap_sens_thres;
msg.payload.tap_config.max_gest_dur = cfg->max_gest_dur;
msg.payload.tap_config.tap_shock_dur = cfg->tap_shock_dur;
msg.payload.tap_config.quite_time_after_gest = cfg->quite_time_after_gest;
msg.payload.tap_config.wait_for_timeout = cfg->wait_for_timeout;
msg.payload.tap_config.axis_sel = cfg->axis_sel;
msg.payload.tap_config.enable_single = cfg->enable_single;
msg.payload.tap_config.enable_double = cfg->enable_double;
msg.payload.tap_config.enable_triple = cfg->enable_triple;
return esp_now_core_send(dest_mac, &msg);
}
static esp_err_t send_unicast_test(const uint8_t *dest_mac, uint32_t seq) { static esp_err_t send_unicast_test(const uint8_t *dest_mac, uint32_t seq) {
alox_EspNowMessage msg = alox_EspNowMessage_init_zero; alox_EspNowMessage msg = alox_EspNowMessage_init_zero;
msg.type = alox_EspNowMessageType_ESPNOW_UNICAST_TEST; msg.type = alox_EspNowMessageType_ESPNOW_UNICAST_TEST;
@@ -387,6 +405,28 @@ esp_err_t esp_now_comm_send_accel_deadzone(const uint8_t mac[CLIENT_MAC_LEN],
return err; return err;
} }
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) {
if (mac == NULL || cfg == 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_tap_config(mac, client_id, cfg);
if (err == ESP_OK) {
ESP_LOGI(TAG,
"unicast SET_TAP_CONFIG to %s: sens=%u client_id=%lu "
"(S=%d D=%d T=%d)",
mac_str, (unsigned)cfg->tap_sens_thres, (unsigned long)client_id,
cfg->enable_single, cfg->enable_double, cfg->enable_triple);
} else {
ESP_LOGW(TAG, "unicast SET_TAP_CONFIG 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], static void handle_accel_sample(const uint8_t mac[CLIENT_MAC_LEN],
const alox_EspNowAccelSample *sample) { const alox_EspNowAccelSample *sample) {
if (sample == NULL) { if (sample == NULL) {
+47
View File
@@ -389,6 +389,48 @@ static void handle_accel_deadzone(const uint8_t *master_mac,
} }
} }
static void handle_tap_config(const uint8_t *master_mac,
const alox_EspNowTapConfig *msg) {
uint32_t my_id = esp_now_core_own_mac()[5];
if (msg->client_id != 0 && msg->client_id != my_id) {
return;
}
if (s_joined && !esp_now_core_mac_equal(master_mac, s_master_mac)) {
return;
}
bma456_tap_config_t cfg = {
.tap_sens_thres = (uint16_t)msg->tap_sens_thres,
.max_gest_dur = (uint16_t)msg->max_gest_dur,
.tap_shock_dur = (uint16_t)msg->tap_shock_dur,
.quite_time_after_gest = (uint16_t)msg->quite_time_after_gest,
.wait_for_timeout = (uint16_t)msg->wait_for_timeout,
.axis_sel = (uint16_t)msg->axis_sel,
.enable_single = msg->enable_single,
.enable_double = msg->enable_double,
.enable_triple = msg->enable_triple,
};
char mac_str[18];
esp_now_core_mac_to_str(master_mac, mac_str, sizeof(mac_str));
ESP_LOGI(TAG,
"tap config from master %s: sens=%u id=%lu (sensor %s)", mac_str,
(unsigned)cfg.tap_sens_thres, (unsigned long)my_id,
bma456_is_ready() ? "ok" : "not installed");
if (!bma456_tap_config_valid(&cfg)) {
ESP_LOGW(TAG, "invalid tap config from master; ignored");
return;
}
if (bma456_set_tap_config(&cfg) != ESP_OK) {
ESP_LOGW(TAG, "tap config apply failed");
return;
}
if (pod_settings_save_tap_config(&cfg) != ESP_OK) {
ESP_LOGW(TAG, "tap config applied but not saved to NVS");
}
}
static void handle_discover(const uint8_t *sender_mac, static void handle_discover(const uint8_t *sender_mac,
const alox_EspNowDiscover *discover) { const alox_EspNowDiscover *discover) {
if (discover->network != esp_now_core_network()) { if (discover->network != esp_now_core_network()) {
@@ -577,6 +619,11 @@ void esp_now_slave_on_recv(const esp_now_recv_info_t *info, const uint8_t *data,
handle_accel_deadzone(info->src_addr, &msg.payload.accel_deadzone); handle_accel_deadzone(info->src_addr, &msg.payload.accel_deadzone);
} }
break; break;
case alox_EspNowMessage_tap_config_tag:
if (from_joined_master(info->src_addr)) {
handle_tap_config(info->src_addr, &msg.payload.tap_config);
}
break;
case alox_EspNowMessage_accel_stream_tag: case alox_EspNowMessage_accel_stream_tag:
if (from_joined_master(info->src_addr)) { if (from_joined_master(info->src_addr)) {
handle_accel_stream(info->src_addr, &msg.payload.accel_stream); handle_accel_stream(info->src_addr, &msg.payload.accel_stream);
+143
View File
@@ -3,13 +3,28 @@
#include "esp_log.h" #include "esp_log.h"
#include "nvs.h" #include "nvs.h"
#include "nvs_flash.h" #include "nvs_flash.h"
#include <string.h>
static const char *TAG = "[SETTINGS]"; static const char *TAG = "[SETTINGS]";
static const char *NS = "powerpod"; static const char *NS = "powerpod";
static const char *KEY_ACCEL_DZ = "accel_dz"; static const char *KEY_ACCEL_DZ = "accel_dz";
static const char *KEY_UV_LATCH = "uv_latch"; static const char *KEY_UV_LATCH = "uv_latch";
static const char *KEY_TAP_CFG = "tap_cfg";
#define ACCEL_DEADZONE_MAX 4095u #define ACCEL_DEADZONE_MAX 4095u
#define TAP_CFG_NVS_VERSION 1u
/** Packed layout for NVS blob (stable across rebuilds). */
typedef struct __attribute__((packed)) {
uint8_t version;
uint16_t tap_sens_thres;
uint16_t max_gest_dur;
uint16_t tap_shock_dur;
uint16_t quite_time_after_gest;
uint16_t wait_for_timeout;
uint16_t axis_sel;
uint8_t enable_flags; /* bit0=single, bit1=double, bit2=triple */
} tap_config_nvs_t;
static bool s_nvs_ready; static bool s_nvs_ready;
@@ -110,6 +125,134 @@ void pod_settings_apply_accel_deadzone(void) {
} }
} }
static void tap_config_to_nvs(const bma456_tap_config_t *cfg,
tap_config_nvs_t *out) {
memset(out, 0, sizeof(*out));
out->version = TAP_CFG_NVS_VERSION;
out->tap_sens_thres = cfg->tap_sens_thres;
out->max_gest_dur = cfg->max_gest_dur;
out->tap_shock_dur = cfg->tap_shock_dur;
out->quite_time_after_gest = cfg->quite_time_after_gest;
out->wait_for_timeout = cfg->wait_for_timeout;
out->axis_sel = cfg->axis_sel;
if (cfg->enable_single) {
out->enable_flags |= 0x01u;
}
if (cfg->enable_double) {
out->enable_flags |= 0x02u;
}
if (cfg->enable_triple) {
out->enable_flags |= 0x04u;
}
}
static bool tap_config_from_nvs(const tap_config_nvs_t *in,
bma456_tap_config_t *cfg) {
if (in->version != TAP_CFG_NVS_VERSION) {
return false;
}
cfg->tap_sens_thres = in->tap_sens_thres;
cfg->max_gest_dur = in->max_gest_dur;
cfg->tap_shock_dur = in->tap_shock_dur;
cfg->quite_time_after_gest = in->quite_time_after_gest;
cfg->wait_for_timeout = in->wait_for_timeout;
cfg->axis_sel = in->axis_sel;
cfg->enable_single = (in->enable_flags & 0x01u) != 0;
cfg->enable_double = (in->enable_flags & 0x02u) != 0;
cfg->enable_triple = (in->enable_flags & 0x04u) != 0;
return bma456_tap_config_valid(cfg);
}
bool pod_settings_load_tap_config(bma456_tap_config_t *cfg_out) {
static const bma456_tap_config_t k_default = BMA456_TAP_CONFIG_DEFAULT;
if (cfg_out == NULL) {
return false;
}
*cfg_out = k_default;
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;
}
tap_config_nvs_t blob = {0};
size_t len = sizeof(blob);
err = nvs_get_blob(handle, KEY_TAP_CFG, &blob, &len);
nvs_close(handle);
if (err == ESP_ERR_NVS_NOT_FOUND) {
return false;
}
if (err != ESP_OK || len != sizeof(blob)) {
ESP_LOGW(TAG, "read tap_cfg failed: %s (len=%u)", esp_err_to_name(err),
(unsigned)len);
return false;
}
if (!tap_config_from_nvs(&blob, cfg_out)) {
ESP_LOGW(TAG, "tap_cfg blob invalid; using defaults");
*cfg_out = k_default;
return false;
}
return true;
}
esp_err_t pod_settings_save_tap_config(const bma456_tap_config_t *cfg) {
if (!bma456_tap_config_valid(cfg)) {
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;
}
tap_config_nvs_t blob;
tap_config_to_nvs(cfg, &blob);
err = nvs_set_blob(handle, KEY_TAP_CFG, &blob, sizeof(blob));
if (err == ESP_OK) {
err = nvs_commit(handle);
}
nvs_close(handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "save tap_cfg failed: %s", esp_err_to_name(err));
return err;
}
ESP_LOGI(TAG,
"saved tap config sens=%u max_gest=%u shock=%u quiet=%u wait=%u "
"axis=%u (S=%d D=%d T=%d)",
(unsigned)cfg->tap_sens_thres, (unsigned)cfg->max_gest_dur,
(unsigned)cfg->tap_shock_dur, (unsigned)cfg->quite_time_after_gest,
(unsigned)cfg->wait_for_timeout, (unsigned)cfg->axis_sel,
cfg->enable_single, cfg->enable_double, cfg->enable_triple);
return ESP_OK;
}
void pod_settings_apply_tap_config(void) {
bma456_tap_config_t cfg;
if (!pod_settings_load_tap_config(&cfg)) {
return;
}
if (!bma456_is_ready()) {
return;
}
if (bma456_set_tap_config(&cfg) != ESP_OK) {
ESP_LOGW(TAG, "failed to apply NVS tap config");
}
}
bool pod_settings_is_uv_latched(void) { bool pod_settings_is_uv_latched(void) {
if (!s_nvs_ready) { if (!s_nvs_ready) {
return false; return false;
+13
View File
@@ -1,6 +1,7 @@
#ifndef POD_SETTINGS_H #ifndef POD_SETTINGS_H
#define POD_SETTINGS_H #define POD_SETTINGS_H
#include "bosch456.h"
#include "esp_err.h" #include "esp_err.h"
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
@@ -17,6 +18,18 @@ uint32_t pod_settings_load_accel_deadzone(void);
/** Apply NVS deadzone to BMA456 when the sensor is present. */ /** Apply NVS deadzone to BMA456 when the sensor is present. */
void pod_settings_apply_accel_deadzone(void); void pod_settings_apply_accel_deadzone(void);
/** Persist local BMA456 tap detection config. */
esp_err_t pod_settings_save_tap_config(const bma456_tap_config_t *cfg);
/**
* Load tap config from NVS into *cfg_out.
* Returns true when a valid blob was loaded; false → compile-time defaults.
*/
bool pod_settings_load_tap_config(bma456_tap_config_t *cfg_out);
/** Apply NVS tap config to BMA456 when the sensor is present. */
void pod_settings_apply_tap_config(void);
/** LiPo under-voltage latch persisted across reboot (software UV protection). */ /** LiPo under-voltage latch persisted across reboot (software UV protection). */
bool pod_settings_is_uv_latched(void); bool pod_settings_is_uv_latched(void);
esp_err_t pod_settings_set_uv_latched(bool latched); esp_err_t pod_settings_set_uv_latched(bool latched);
+3
View File
@@ -3,6 +3,7 @@
#include "cmd_accel_deadzone.h" #include "cmd_accel_deadzone.h"
#include "cmd_accel_stream.h" #include "cmd_accel_stream.h"
#include "cmd_tap_notify.h" #include "cmd_tap_notify.h"
#include "cmd_tap_config.h"
#include "cmd_cache_status.h" #include "cmd_cache_status.h"
#include "cmd_espnow_unicast_test.h" #include "cmd_espnow_unicast_test.h"
#include "cmd_espnow_echo_ping.h" #include "cmd_espnow_echo_ping.h"
@@ -150,6 +151,7 @@ void app_main(void) {
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 { } else {
pod_settings_apply_accel_deadzone(); pod_settings_apply_accel_deadzone();
pod_settings_apply_tap_config();
} }
} }
@@ -197,6 +199,7 @@ void app_main(void) {
cmd_accel_deadzone_register(); cmd_accel_deadzone_register();
cmd_accel_stream_register(); cmd_accel_stream_register();
cmd_tap_notify_register(); cmd_tap_notify_register();
cmd_tap_config_register();
cmd_cache_status_register(); cmd_cache_status_register();
cmd_espnow_unicast_test_register(); cmd_espnow_unicast_test_register();
cmd_espnow_echo_ping_register(); cmd_espnow_echo_ping_register();
+3
View File
@@ -42,6 +42,9 @@ PB_BIND(alox_EspNowBatteryQuery, alox_EspNowBatteryQuery, AUTO)
PB_BIND(alox_EspNowTapNotify, alox_EspNowTapNotify, AUTO) PB_BIND(alox_EspNowTapNotify, alox_EspNowTapNotify, AUTO)
PB_BIND(alox_EspNowTapConfig, alox_EspNowTapConfig, AUTO)
PB_BIND(alox_EspNowTapEvent, alox_EspNowTapEvent, AUTO) PB_BIND(alox_EspNowTapEvent, alox_EspNowTapEvent, AUTO)
+53 -4
View File
@@ -31,7 +31,8 @@ typedef enum _alox_EspNowMessageType {
alox_EspNowMessageType_ESPNOW_SET_TAP_NOTIFY = 17, alox_EspNowMessageType_ESPNOW_SET_TAP_NOTIFY = 17,
alox_EspNowMessageType_ESPNOW_TAP_EVENT = 18, alox_EspNowMessageType_ESPNOW_TAP_EVENT = 18,
alox_EspNowMessageType_ESPNOW_ECHO_PING = 19, alox_EspNowMessageType_ESPNOW_ECHO_PING = 19,
alox_EspNowMessageType_ESPNOW_ECHO_PONG = 20 alox_EspNowMessageType_ESPNOW_ECHO_PONG = 20,
alox_EspNowMessageType_ESPNOW_SET_TAP_CONFIG = 21
} alox_EspNowMessageType; } alox_EspNowMessageType;
/* Struct definitions */ /* Struct definitions */
@@ -110,6 +111,20 @@ typedef struct _alox_EspNowTapNotify {
bool triple; bool triple;
} alox_EspNowTapNotify; } alox_EspNowTapNotify;
/* * Master → slave: BMA456H multitap detection parameters. */
typedef struct _alox_EspNowTapConfig {
uint32_t client_id; /* 0 = all slaves; otherwise only matching slave_id applies */
uint32_t tap_sens_thres;
uint32_t max_gest_dur;
uint32_t tap_shock_dur;
uint32_t quite_time_after_gest;
uint32_t wait_for_timeout;
uint32_t axis_sel;
bool enable_single;
bool enable_double;
bool enable_triple;
} alox_EspNowTapConfig;
/* * Slave → master: tap detected on BMA456 (event, not periodic). */ /* * Slave → master: tap detected on BMA456 (event, not periodic). */
typedef struct _alox_EspNowTapEvent { typedef struct _alox_EspNowTapEvent {
uint32_t slave_id; uint32_t slave_id;
@@ -188,6 +203,7 @@ typedef struct _alox_EspNowMessage {
alox_EspNowTapEvent tap_event; alox_EspNowTapEvent tap_event;
alox_EspNowEchoPing echo_ping; alox_EspNowEchoPing echo_ping;
alox_EspNowEchoPong echo_pong; alox_EspNowEchoPong echo_pong;
alox_EspNowTapConfig tap_config;
} payload; } payload;
} alox_EspNowMessage; } alox_EspNowMessage;
@@ -198,8 +214,9 @@ extern "C" {
/* Helper constants for enums */ /* Helper constants for enums */
#define _alox_EspNowMessageType_MIN alox_EspNowMessageType_ESPNOW_UNKNOWN #define _alox_EspNowMessageType_MIN alox_EspNowMessageType_ESPNOW_UNKNOWN
#define _alox_EspNowMessageType_MAX alox_EspNowMessageType_ESPNOW_ECHO_PONG #define _alox_EspNowMessageType_MAX alox_EspNowMessageType_ESPNOW_SET_TAP_CONFIG
#define _alox_EspNowMessageType_ARRAYSIZE ((alox_EspNowMessageType)(alox_EspNowMessageType_ESPNOW_ECHO_PONG+1)) #define _alox_EspNowMessageType_ARRAYSIZE ((alox_EspNowMessageType)(alox_EspNowMessageType_ESPNOW_SET_TAP_CONFIG+1))
@@ -236,6 +253,7 @@ extern "C" {
#define alox_EspNowAccelSample_init_default {0, 0, 0, 0} #define alox_EspNowAccelSample_init_default {0, 0, 0, 0}
#define alox_EspNowBatteryQuery_init_default {0} #define alox_EspNowBatteryQuery_init_default {0}
#define alox_EspNowTapNotify_init_default {0, 0, 0, 0} #define alox_EspNowTapNotify_init_default {0, 0, 0, 0}
#define alox_EspNowTapConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define alox_EspNowTapEvent_init_default {0, 0} #define alox_EspNowTapEvent_init_default {0, 0}
#define alox_EspNowBatteryReport_init_default {0, 0, 0, 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_EspNowLedRing_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
@@ -256,6 +274,7 @@ extern "C" {
#define alox_EspNowAccelSample_init_zero {0, 0, 0, 0} #define alox_EspNowAccelSample_init_zero {0, 0, 0, 0}
#define alox_EspNowBatteryQuery_init_zero {0} #define alox_EspNowBatteryQuery_init_zero {0}
#define alox_EspNowTapNotify_init_zero {0, 0, 0, 0} #define alox_EspNowTapNotify_init_zero {0, 0, 0, 0}
#define alox_EspNowTapConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define alox_EspNowTapEvent_init_zero {0, 0} #define alox_EspNowTapEvent_init_zero {0, 0}
#define alox_EspNowBatteryReport_init_zero {0, 0, 0, 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_EspNowLedRing_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
@@ -294,6 +313,16 @@ extern "C" {
#define alox_EspNowTapNotify_single_tag 2 #define alox_EspNowTapNotify_single_tag 2
#define alox_EspNowTapNotify_double_tap_tag 3 #define alox_EspNowTapNotify_double_tap_tag 3
#define alox_EspNowTapNotify_triple_tag 4 #define alox_EspNowTapNotify_triple_tag 4
#define alox_EspNowTapConfig_client_id_tag 1
#define alox_EspNowTapConfig_tap_sens_thres_tag 2
#define alox_EspNowTapConfig_max_gest_dur_tag 3
#define alox_EspNowTapConfig_tap_shock_dur_tag 4
#define alox_EspNowTapConfig_quite_time_after_gest_tag 5
#define alox_EspNowTapConfig_wait_for_timeout_tag 6
#define alox_EspNowTapConfig_axis_sel_tag 7
#define alox_EspNowTapConfig_enable_single_tag 8
#define alox_EspNowTapConfig_enable_double_tag 9
#define alox_EspNowTapConfig_enable_triple_tag 10
#define alox_EspNowTapEvent_slave_id_tag 1 #define alox_EspNowTapEvent_slave_id_tag 1
#define alox_EspNowTapEvent_kind_tag 2 #define alox_EspNowTapEvent_kind_tag 2
#define alox_EspNowBatteryReport_client_id_tag 1 #define alox_EspNowBatteryReport_client_id_tag 1
@@ -338,6 +367,7 @@ extern "C" {
#define alox_EspNowMessage_tap_event_tag 19 #define alox_EspNowMessage_tap_event_tag 19
#define alox_EspNowMessage_echo_ping_tag 20 #define alox_EspNowMessage_echo_ping_tag 20
#define alox_EspNowMessage_echo_pong_tag 21 #define alox_EspNowMessage_echo_pong_tag 21
#define alox_EspNowMessage_tap_config_tag 22
/* Struct field encoding specification for nanopb */ /* Struct field encoding specification for nanopb */
#define alox_EspNowUnicastTest_FIELDLIST(X, a) \ #define alox_EspNowUnicastTest_FIELDLIST(X, a) \
@@ -416,6 +446,20 @@ X(a, STATIC, SINGULAR, BOOL, triple, 4)
#define alox_EspNowTapNotify_CALLBACK NULL #define alox_EspNowTapNotify_CALLBACK NULL
#define alox_EspNowTapNotify_DEFAULT NULL #define alox_EspNowTapNotify_DEFAULT NULL
#define alox_EspNowTapConfig_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, client_id, 1) \
X(a, STATIC, SINGULAR, UINT32, tap_sens_thres, 2) \
X(a, STATIC, SINGULAR, UINT32, max_gest_dur, 3) \
X(a, STATIC, SINGULAR, UINT32, tap_shock_dur, 4) \
X(a, STATIC, SINGULAR, UINT32, quite_time_after_gest, 5) \
X(a, STATIC, SINGULAR, UINT32, wait_for_timeout, 6) \
X(a, STATIC, SINGULAR, UINT32, axis_sel, 7) \
X(a, STATIC, SINGULAR, BOOL, enable_single, 8) \
X(a, STATIC, SINGULAR, BOOL, enable_double, 9) \
X(a, STATIC, SINGULAR, BOOL, enable_triple, 10)
#define alox_EspNowTapConfig_CALLBACK NULL
#define alox_EspNowTapConfig_DEFAULT NULL
#define alox_EspNowTapEvent_FIELDLIST(X, a) \ #define alox_EspNowTapEvent_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, slave_id, 1) \ X(a, STATIC, SINGULAR, UINT32, slave_id, 1) \
X(a, STATIC, SINGULAR, UINT32, kind, 2) X(a, STATIC, SINGULAR, UINT32, kind, 2)
@@ -489,7 +533,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload,battery_report,payload.battery_repor
X(a, STATIC, ONEOF, MESSAGE, (payload,tap_notify,payload.tap_notify), 18) \ X(a, STATIC, ONEOF, MESSAGE, (payload,tap_notify,payload.tap_notify), 18) \
X(a, STATIC, ONEOF, MESSAGE, (payload,tap_event,payload.tap_event), 19) \ X(a, STATIC, ONEOF, MESSAGE, (payload,tap_event,payload.tap_event), 19) \
X(a, STATIC, ONEOF, MESSAGE, (payload,echo_ping,payload.echo_ping), 20) \ X(a, STATIC, ONEOF, MESSAGE, (payload,echo_ping,payload.echo_ping), 20) \
X(a, STATIC, ONEOF, MESSAGE, (payload,echo_pong,payload.echo_pong), 21) X(a, STATIC, ONEOF, MESSAGE, (payload,echo_pong,payload.echo_pong), 21) \
X(a, STATIC, ONEOF, MESSAGE, (payload,tap_config,payload.tap_config), 22)
#define alox_EspNowMessage_CALLBACK NULL #define alox_EspNowMessage_CALLBACK NULL
#define alox_EspNowMessage_DEFAULT NULL #define alox_EspNowMessage_DEFAULT NULL
#define alox_EspNowMessage_payload_discover_MSGTYPE alox_EspNowDiscover #define alox_EspNowMessage_payload_discover_MSGTYPE alox_EspNowDiscover
@@ -512,6 +557,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload,echo_pong,payload.echo_pong), 21)
#define alox_EspNowMessage_payload_tap_event_MSGTYPE alox_EspNowTapEvent #define alox_EspNowMessage_payload_tap_event_MSGTYPE alox_EspNowTapEvent
#define alox_EspNowMessage_payload_echo_ping_MSGTYPE alox_EspNowEchoPing #define alox_EspNowMessage_payload_echo_ping_MSGTYPE alox_EspNowEchoPing
#define alox_EspNowMessage_payload_echo_pong_MSGTYPE alox_EspNowEchoPong #define alox_EspNowMessage_payload_echo_pong_MSGTYPE alox_EspNowEchoPong
#define alox_EspNowMessage_payload_tap_config_MSGTYPE alox_EspNowTapConfig
extern const pb_msgdesc_t alox_EspNowUnicastTest_msg; extern const pb_msgdesc_t alox_EspNowUnicastTest_msg;
extern const pb_msgdesc_t alox_EspNowEchoPing_msg; extern const pb_msgdesc_t alox_EspNowEchoPing_msg;
@@ -525,6 +571,7 @@ extern const pb_msgdesc_t alox_EspNowAccelStream_msg;
extern const pb_msgdesc_t alox_EspNowAccelSample_msg; extern const pb_msgdesc_t alox_EspNowAccelSample_msg;
extern const pb_msgdesc_t alox_EspNowBatteryQuery_msg; extern const pb_msgdesc_t alox_EspNowBatteryQuery_msg;
extern const pb_msgdesc_t alox_EspNowTapNotify_msg; 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_EspNowTapEvent_msg;
extern const pb_msgdesc_t alox_EspNowBatteryReport_msg; extern const pb_msgdesc_t alox_EspNowBatteryReport_msg;
extern const pb_msgdesc_t alox_EspNowLedRing_msg; extern const pb_msgdesc_t alox_EspNowLedRing_msg;
@@ -547,6 +594,7 @@ extern const pb_msgdesc_t alox_EspNowMessage_msg;
#define alox_EspNowAccelSample_fields &alox_EspNowAccelSample_msg #define alox_EspNowAccelSample_fields &alox_EspNowAccelSample_msg
#define alox_EspNowBatteryQuery_fields &alox_EspNowBatteryQuery_msg #define alox_EspNowBatteryQuery_fields &alox_EspNowBatteryQuery_msg
#define alox_EspNowTapNotify_fields &alox_EspNowTapNotify_msg #define alox_EspNowTapNotify_fields &alox_EspNowTapNotify_msg
#define alox_EspNowTapConfig_fields &alox_EspNowTapConfig_msg
#define alox_EspNowTapEvent_fields &alox_EspNowTapEvent_msg #define alox_EspNowTapEvent_fields &alox_EspNowTapEvent_msg
#define alox_EspNowBatteryReport_fields &alox_EspNowBatteryReport_msg #define alox_EspNowBatteryReport_fields &alox_EspNowBatteryReport_msg
#define alox_EspNowLedRing_fields &alox_EspNowLedRing_msg #define alox_EspNowLedRing_fields &alox_EspNowLedRing_msg
@@ -575,6 +623,7 @@ extern const pb_msgdesc_t alox_EspNowMessage_msg;
#define alox_EspNowOtaStart_size 6 #define alox_EspNowOtaStart_size 6
#define alox_EspNowOtaStatus_size 18 #define alox_EspNowOtaStatus_size 18
#define alox_EspNowRestart_size 6 #define alox_EspNowRestart_size 6
#define alox_EspNowTapConfig_size 48
#define alox_EspNowTapEvent_size 12 #define alox_EspNowTapEvent_size 12
#define alox_EspNowTapNotify_size 12 #define alox_EspNowTapNotify_size 12
#define alox_EspNowUnicastTest_size 6 #define alox_EspNowUnicastTest_size 6
+16
View File
@@ -26,6 +26,7 @@ enum EspNowMessageType {
ESPNOW_TAP_EVENT = 18; ESPNOW_TAP_EVENT = 18;
ESPNOW_ECHO_PING = 19; ESPNOW_ECHO_PING = 19;
ESPNOW_ECHO_PONG = 20; ESPNOW_ECHO_PONG = 20;
ESPNOW_SET_TAP_CONFIG = 21;
} }
message EspNowUnicastTest { message EspNowUnicastTest {
@@ -103,6 +104,20 @@ message EspNowTapNotify {
bool triple = 4; bool triple = 4;
} }
/** Master → slave: BMA456H multitap detection parameters. */
message EspNowTapConfig {
uint32 client_id = 1; // 0 = all slaves; otherwise only matching slave_id applies
uint32 tap_sens_thres = 2;
uint32 max_gest_dur = 3;
uint32 tap_shock_dur = 4;
uint32 quite_time_after_gest = 5;
uint32 wait_for_timeout = 6;
uint32 axis_sel = 7;
bool enable_single = 8;
bool enable_double = 9;
bool enable_triple = 10;
}
/** Slave → master: tap detected on BMA456 (event, not periodic). */ /** Slave → master: tap detected on BMA456 (event, not periodic). */
message EspNowTapEvent { message EspNowTapEvent {
uint32 slave_id = 1; uint32 slave_id = 1;
@@ -177,5 +192,6 @@ message EspNowMessage {
EspNowTapEvent tap_event = 19; EspNowTapEvent tap_event = 19;
EspNowEchoPing echo_ping = 20; EspNowEchoPing echo_ping = 20;
EspNowEchoPong echo_pong = 21; EspNowEchoPong echo_pong = 21;
EspNowTapConfig tap_config = 22;
} }
} }
+6
View File
@@ -117,6 +117,12 @@ PB_BIND(alox_SetLogLevelRequest, alox_SetLogLevelRequest, AUTO)
PB_BIND(alox_SetLogLevelResponse, alox_SetLogLevelResponse, AUTO) PB_BIND(alox_SetLogLevelResponse, alox_SetLogLevelResponse, AUTO)
PB_BIND(alox_TapConfigRequest, alox_TapConfigRequest, AUTO)
PB_BIND(alox_TapConfigResponse, alox_TapConfigResponse, AUTO)
PB_BIND(alox_OtaStartPayload, alox_OtaStartPayload, AUTO) PB_BIND(alox_OtaStartPayload, alox_OtaStartPayload, AUTO)
+114 -4
View File
@@ -36,7 +36,9 @@ typedef enum _alox_MessageType {
/* * Host → master → slave → master: timestamp echo round-trip (latency test). */ /* * Host → master → slave → master: timestamp echo round-trip (latency test). */
alox_MessageType_ESPNOW_ECHO_PING = 30, alox_MessageType_ESPNOW_ECHO_PING = 30,
/* * Host → master: get/set ESP-IDF log level for tag "*" (global). */ /* * Host → master: get/set ESP-IDF log level for tag "*" (global). */
alox_MessageType_SET_LOG_LEVEL = 31 alox_MessageType_SET_LOG_LEVEL = 31,
/* * Host → master: get/set BMA456H multitap detection parameters. */
alox_MessageType_TAP_CONFIG = 32
} alox_MessageType; } alox_MessageType;
typedef enum _alox_TapKind { typedef enum _alox_TapKind {
@@ -321,6 +323,38 @@ typedef struct _alox_SetLogLevelResponse {
uint32_t level; uint32_t level;
} alox_SetLogLevelResponse; } alox_SetLogLevelResponse;
/* write=false: read tap config; write=true: apply + persist on target node.
client_id 0 = local BMA456; >0 = slave id on master; all_clients = push to all slaves. */
typedef struct _alox_TapConfigRequest {
bool write;
uint32_t client_id;
bool all_clients;
uint32_t tap_sens_thres;
uint32_t max_gest_dur;
uint32_t tap_shock_dur;
uint32_t quite_time_after_gest;
uint32_t wait_for_timeout;
uint32_t axis_sel;
bool enable_single;
bool enable_double;
bool enable_triple;
} alox_TapConfigRequest;
typedef struct _alox_TapConfigResponse {
uint32_t client_id;
bool success;
uint32_t slaves_updated;
uint32_t tap_sens_thres;
uint32_t max_gest_dur;
uint32_t tap_shock_dur;
uint32_t quite_time_after_gest;
uint32_t wait_for_timeout;
uint32_t axis_sel;
bool enable_single;
bool enable_double;
bool enable_triple;
} alox_TapConfigResponse;
/* Host → device: begin UART OTA (erase inactive OTA slot; device replies OTA_STATUS). */ /* Host → device: begin UART OTA (erase inactive OTA slot; device replies OTA_STATUS). */
typedef struct _alox_OtaStartPayload { typedef struct _alox_OtaStartPayload {
uint32_t total_size; uint32_t total_size;
@@ -407,6 +441,8 @@ typedef struct _alox_UartMessage {
alox_EspNowEchoPingResponse espnow_echo_ping_response; alox_EspNowEchoPingResponse espnow_echo_ping_response;
alox_SetLogLevelRequest set_log_level_request; alox_SetLogLevelRequest set_log_level_request;
alox_SetLogLevelResponse set_log_level_response; alox_SetLogLevelResponse set_log_level_response;
alox_TapConfigRequest tap_config_request;
alox_TapConfigResponse tap_config_response;
} payload; } payload;
} alox_UartMessage; } alox_UartMessage;
@@ -417,8 +453,8 @@ extern "C" {
/* Helper constants for enums */ /* Helper constants for enums */
#define _alox_MessageType_MIN alox_MessageType_UNKNOWN #define _alox_MessageType_MIN alox_MessageType_UNKNOWN
#define _alox_MessageType_MAX alox_MessageType_SET_LOG_LEVEL #define _alox_MessageType_MAX alox_MessageType_TAP_CONFIG
#define _alox_MessageType_ARRAYSIZE ((alox_MessageType)(alox_MessageType_SET_LOG_LEVEL+1)) #define _alox_MessageType_ARRAYSIZE ((alox_MessageType)(alox_MessageType_TAP_CONFIG+1))
#define _alox_TapKind_MIN alox_TapKind_TAP_NONE #define _alox_TapKind_MIN alox_TapKind_TAP_NONE
#define _alox_TapKind_MAX alox_TapKind_TAP_TRIPLE #define _alox_TapKind_MAX alox_TapKind_TAP_TRIPLE
@@ -469,6 +505,8 @@ extern "C" {
@@ -510,6 +548,8 @@ extern "C" {
#define alox_RestartResponse_init_default {0, 0} #define alox_RestartResponse_init_default {0, 0}
#define alox_SetLogLevelRequest_init_default {0, 0} #define alox_SetLogLevelRequest_init_default {0, 0}
#define alox_SetLogLevelResponse_init_default {0, 0} #define alox_SetLogLevelResponse_init_default {0, 0}
#define alox_TapConfigRequest_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define alox_TapConfigResponse_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define alox_OtaStartPayload_init_default {0} #define alox_OtaStartPayload_init_default {0}
#define alox_OtaPayload_init_default {0, {0, {0}}} #define alox_OtaPayload_init_default {0, {0, {0}}}
#define alox_OtaEndPayload_init_default {0} #define alox_OtaEndPayload_init_default {0}
@@ -554,6 +594,8 @@ extern "C" {
#define alox_RestartResponse_init_zero {0, 0} #define alox_RestartResponse_init_zero {0, 0}
#define alox_SetLogLevelRequest_init_zero {0, 0} #define alox_SetLogLevelRequest_init_zero {0, 0}
#define alox_SetLogLevelResponse_init_zero {0, 0} #define alox_SetLogLevelResponse_init_zero {0, 0}
#define alox_TapConfigRequest_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define alox_TapConfigResponse_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define alox_OtaStartPayload_init_zero {0} #define alox_OtaStartPayload_init_zero {0}
#define alox_OtaPayload_init_zero {0, {0, {0}}} #define alox_OtaPayload_init_zero {0, {0, {0}}}
#define alox_OtaEndPayload_init_zero {0} #define alox_OtaEndPayload_init_zero {0}
@@ -681,6 +723,30 @@ extern "C" {
#define alox_SetLogLevelRequest_level_tag 2 #define alox_SetLogLevelRequest_level_tag 2
#define alox_SetLogLevelResponse_success_tag 1 #define alox_SetLogLevelResponse_success_tag 1
#define alox_SetLogLevelResponse_level_tag 2 #define alox_SetLogLevelResponse_level_tag 2
#define alox_TapConfigRequest_write_tag 1
#define alox_TapConfigRequest_client_id_tag 2
#define alox_TapConfigRequest_all_clients_tag 3
#define alox_TapConfigRequest_tap_sens_thres_tag 4
#define alox_TapConfigRequest_max_gest_dur_tag 5
#define alox_TapConfigRequest_tap_shock_dur_tag 6
#define alox_TapConfigRequest_quite_time_after_gest_tag 7
#define alox_TapConfigRequest_wait_for_timeout_tag 8
#define alox_TapConfigRequest_axis_sel_tag 9
#define alox_TapConfigRequest_enable_single_tag 10
#define alox_TapConfigRequest_enable_double_tag 11
#define alox_TapConfigRequest_enable_triple_tag 12
#define alox_TapConfigResponse_client_id_tag 1
#define alox_TapConfigResponse_success_tag 2
#define alox_TapConfigResponse_slaves_updated_tag 3
#define alox_TapConfigResponse_tap_sens_thres_tag 4
#define alox_TapConfigResponse_max_gest_dur_tag 5
#define alox_TapConfigResponse_tap_shock_dur_tag 6
#define alox_TapConfigResponse_quite_time_after_gest_tag 7
#define alox_TapConfigResponse_wait_for_timeout_tag 8
#define alox_TapConfigResponse_axis_sel_tag 9
#define alox_TapConfigResponse_enable_single_tag 10
#define alox_TapConfigResponse_enable_double_tag 11
#define alox_TapConfigResponse_enable_triple_tag 12
#define alox_OtaStartPayload_total_size_tag 1 #define alox_OtaStartPayload_total_size_tag 1
#define alox_OtaPayload_seq_tag 1 #define alox_OtaPayload_seq_tag 1
#define alox_OtaPayload_data_tag 2 #define alox_OtaPayload_data_tag 2
@@ -733,6 +799,8 @@ extern "C" {
#define alox_UartMessage_espnow_echo_ping_response_tag 36 #define alox_UartMessage_espnow_echo_ping_response_tag 36
#define alox_UartMessage_set_log_level_request_tag 37 #define alox_UartMessage_set_log_level_request_tag 37
#define alox_UartMessage_set_log_level_response_tag 38 #define alox_UartMessage_set_log_level_response_tag 38
#define alox_UartMessage_tap_config_request_tag 39
#define alox_UartMessage_tap_config_response_tag 40
/* Struct field encoding specification for nanopb */ /* Struct field encoding specification for nanopb */
#define alox_UartMessage_FIELDLIST(X, a) \ #define alox_UartMessage_FIELDLIST(X, a) \
@@ -769,7 +837,9 @@ X(a, STATIC, ONEOF, MESSAGE, (payload,cache_status_response,payload.cache_
X(a, STATIC, ONEOF, MESSAGE, (payload,espnow_echo_ping_request,payload.espnow_echo_ping_request), 35) \ X(a, STATIC, ONEOF, MESSAGE, (payload,espnow_echo_ping_request,payload.espnow_echo_ping_request), 35) \
X(a, STATIC, ONEOF, MESSAGE, (payload,espnow_echo_ping_response,payload.espnow_echo_ping_response), 36) \ X(a, STATIC, ONEOF, MESSAGE, (payload,espnow_echo_ping_response,payload.espnow_echo_ping_response), 36) \
X(a, STATIC, ONEOF, MESSAGE, (payload,set_log_level_request,payload.set_log_level_request), 37) \ X(a, STATIC, ONEOF, MESSAGE, (payload,set_log_level_request,payload.set_log_level_request), 37) \
X(a, STATIC, ONEOF, MESSAGE, (payload,set_log_level_response,payload.set_log_level_response), 38) X(a, STATIC, ONEOF, MESSAGE, (payload,set_log_level_response,payload.set_log_level_response), 38) \
X(a, STATIC, ONEOF, MESSAGE, (payload,tap_config_request,payload.tap_config_request), 39) \
X(a, STATIC, ONEOF, MESSAGE, (payload,tap_config_response,payload.tap_config_response), 40)
#define alox_UartMessage_CALLBACK NULL #define alox_UartMessage_CALLBACK NULL
#define alox_UartMessage_DEFAULT NULL #define alox_UartMessage_DEFAULT NULL
#define alox_UartMessage_payload_ack_payload_MSGTYPE alox_Ack #define alox_UartMessage_payload_ack_payload_MSGTYPE alox_Ack
@@ -805,6 +875,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload,set_log_level_response,payload.set_l
#define alox_UartMessage_payload_espnow_echo_ping_response_MSGTYPE alox_EspNowEchoPingResponse #define alox_UartMessage_payload_espnow_echo_ping_response_MSGTYPE alox_EspNowEchoPingResponse
#define alox_UartMessage_payload_set_log_level_request_MSGTYPE alox_SetLogLevelRequest #define alox_UartMessage_payload_set_log_level_request_MSGTYPE alox_SetLogLevelRequest
#define alox_UartMessage_payload_set_log_level_response_MSGTYPE alox_SetLogLevelResponse #define alox_UartMessage_payload_set_log_level_response_MSGTYPE alox_SetLogLevelResponse
#define alox_UartMessage_payload_tap_config_request_MSGTYPE alox_TapConfigRequest
#define alox_UartMessage_payload_tap_config_response_MSGTYPE alox_TapConfigResponse
#define alox_Ack_FIELDLIST(X, a) \ #define alox_Ack_FIELDLIST(X, a) \
@@ -1078,6 +1150,38 @@ X(a, STATIC, SINGULAR, UINT32, level, 2)
#define alox_SetLogLevelResponse_CALLBACK NULL #define alox_SetLogLevelResponse_CALLBACK NULL
#define alox_SetLogLevelResponse_DEFAULT NULL #define alox_SetLogLevelResponse_DEFAULT NULL
#define alox_TapConfigRequest_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, BOOL, write, 1) \
X(a, STATIC, SINGULAR, UINT32, client_id, 2) \
X(a, STATIC, SINGULAR, BOOL, all_clients, 3) \
X(a, STATIC, SINGULAR, UINT32, tap_sens_thres, 4) \
X(a, STATIC, SINGULAR, UINT32, max_gest_dur, 5) \
X(a, STATIC, SINGULAR, UINT32, tap_shock_dur, 6) \
X(a, STATIC, SINGULAR, UINT32, quite_time_after_gest, 7) \
X(a, STATIC, SINGULAR, UINT32, wait_for_timeout, 8) \
X(a, STATIC, SINGULAR, UINT32, axis_sel, 9) \
X(a, STATIC, SINGULAR, BOOL, enable_single, 10) \
X(a, STATIC, SINGULAR, BOOL, enable_double, 11) \
X(a, STATIC, SINGULAR, BOOL, enable_triple, 12)
#define alox_TapConfigRequest_CALLBACK NULL
#define alox_TapConfigRequest_DEFAULT NULL
#define alox_TapConfigResponse_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, client_id, 1) \
X(a, STATIC, SINGULAR, BOOL, success, 2) \
X(a, STATIC, SINGULAR, UINT32, slaves_updated, 3) \
X(a, STATIC, SINGULAR, UINT32, tap_sens_thres, 4) \
X(a, STATIC, SINGULAR, UINT32, max_gest_dur, 5) \
X(a, STATIC, SINGULAR, UINT32, tap_shock_dur, 6) \
X(a, STATIC, SINGULAR, UINT32, quite_time_after_gest, 7) \
X(a, STATIC, SINGULAR, UINT32, wait_for_timeout, 8) \
X(a, STATIC, SINGULAR, UINT32, axis_sel, 9) \
X(a, STATIC, SINGULAR, BOOL, enable_single, 10) \
X(a, STATIC, SINGULAR, BOOL, enable_double, 11) \
X(a, STATIC, SINGULAR, BOOL, enable_triple, 12)
#define alox_TapConfigResponse_CALLBACK NULL
#define alox_TapConfigResponse_DEFAULT NULL
#define alox_OtaStartPayload_FIELDLIST(X, a) \ #define alox_OtaStartPayload_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, total_size, 1) X(a, STATIC, SINGULAR, UINT32, total_size, 1)
#define alox_OtaStartPayload_CALLBACK NULL #define alox_OtaStartPayload_CALLBACK NULL
@@ -1163,6 +1267,8 @@ extern const pb_msgdesc_t alox_RestartRequest_msg;
extern const pb_msgdesc_t alox_RestartResponse_msg; extern const pb_msgdesc_t alox_RestartResponse_msg;
extern const pb_msgdesc_t alox_SetLogLevelRequest_msg; extern const pb_msgdesc_t alox_SetLogLevelRequest_msg;
extern const pb_msgdesc_t alox_SetLogLevelResponse_msg; extern const pb_msgdesc_t alox_SetLogLevelResponse_msg;
extern const pb_msgdesc_t alox_TapConfigRequest_msg;
extern const pb_msgdesc_t alox_TapConfigResponse_msg;
extern const pb_msgdesc_t alox_OtaStartPayload_msg; extern const pb_msgdesc_t alox_OtaStartPayload_msg;
extern const pb_msgdesc_t alox_OtaPayload_msg; extern const pb_msgdesc_t alox_OtaPayload_msg;
extern const pb_msgdesc_t alox_OtaEndPayload_msg; extern const pb_msgdesc_t alox_OtaEndPayload_msg;
@@ -1209,6 +1315,8 @@ extern const pb_msgdesc_t alox_OtaSlaveProgressResponse_msg;
#define alox_RestartResponse_fields &alox_RestartResponse_msg #define alox_RestartResponse_fields &alox_RestartResponse_msg
#define alox_SetLogLevelRequest_fields &alox_SetLogLevelRequest_msg #define alox_SetLogLevelRequest_fields &alox_SetLogLevelRequest_msg
#define alox_SetLogLevelResponse_fields &alox_SetLogLevelResponse_msg #define alox_SetLogLevelResponse_fields &alox_SetLogLevelResponse_msg
#define alox_TapConfigRequest_fields &alox_TapConfigRequest_msg
#define alox_TapConfigResponse_fields &alox_TapConfigResponse_msg
#define alox_OtaStartPayload_fields &alox_OtaStartPayload_msg #define alox_OtaStartPayload_fields &alox_OtaStartPayload_msg
#define alox_OtaPayload_fields &alox_OtaPayload_msg #define alox_OtaPayload_fields &alox_OtaPayload_msg
#define alox_OtaEndPayload_fields &alox_OtaEndPayload_msg #define alox_OtaEndPayload_fields &alox_OtaEndPayload_msg
@@ -1260,6 +1368,8 @@ extern const pb_msgdesc_t alox_OtaSlaveProgressResponse_msg;
#define alox_RestartResponse_size 8 #define alox_RestartResponse_size 8
#define alox_SetLogLevelRequest_size 8 #define alox_SetLogLevelRequest_size 8
#define alox_SetLogLevelResponse_size 8 #define alox_SetLogLevelResponse_size 8
#define alox_TapConfigRequest_size 52
#define alox_TapConfigResponse_size 56
#define alox_TapEvent_size 16 #define alox_TapEvent_size 16
#define alox_TapNotifyRequest_size 16 #define alox_TapNotifyRequest_size 16
#define alox_TapNotifyResponse_size 20 #define alox_TapNotifyResponse_size 20
+36
View File
@@ -33,6 +33,8 @@ enum MessageType {
ESPNOW_ECHO_PING = 30; ESPNOW_ECHO_PING = 30;
/** Host → master: get/set ESP-IDF log level for tag "*" (global). */ /** Host → master: get/set ESP-IDF log level for tag "*" (global). */
SET_LOG_LEVEL = 31; SET_LOG_LEVEL = 31;
/** Host → master: get/set BMA456H multitap detection parameters. */
TAP_CONFIG = 32;
} }
message UartMessage { message UartMessage {
@@ -71,6 +73,8 @@ message UartMessage {
EspNowEchoPingResponse espnow_echo_ping_response = 36; EspNowEchoPingResponse espnow_echo_ping_response = 36;
SetLogLevelRequest set_log_level_request = 37; SetLogLevelRequest set_log_level_request = 37;
SetLogLevelResponse set_log_level_response = 38; SetLogLevelResponse set_log_level_response = 38;
TapConfigRequest tap_config_request = 39;
TapConfigResponse tap_config_response = 40;
} }
} }
@@ -345,6 +349,38 @@ message SetLogLevelResponse {
uint32 level = 2; uint32 level = 2;
} }
// write=false: read tap config; write=true: apply + persist on target node.
// client_id 0 = local BMA456; >0 = slave id on master; all_clients = push to all slaves.
message TapConfigRequest {
bool write = 1;
uint32 client_id = 2;
bool all_clients = 3;
uint32 tap_sens_thres = 4;
uint32 max_gest_dur = 5;
uint32 tap_shock_dur = 6;
uint32 quite_time_after_gest = 7;
uint32 wait_for_timeout = 8;
uint32 axis_sel = 9;
bool enable_single = 10;
bool enable_double = 11;
bool enable_triple = 12;
}
message TapConfigResponse {
uint32 client_id = 1;
bool success = 2;
uint32 slaves_updated = 3;
uint32 tap_sens_thres = 4;
uint32 max_gest_dur = 5;
uint32 tap_shock_dur = 6;
uint32 quite_time_after_gest = 7;
uint32 wait_for_timeout = 8;
uint32 axis_sel = 9;
bool enable_single = 10;
bool enable_double = 11;
bool enable_triple = 12;
}
// Host → device: begin UART OTA (erase inactive OTA slot; device replies OTA_STATUS). // Host → device: begin UART OTA (erase inactive OTA slot; device replies OTA_STATUS).
message OtaStartPayload { message OtaStartPayload {
uint32 total_size = 1; uint32 total_size = 1;