Add selectable ESP-NOW send path for accel/tap input.
Expose best_effort/fast/wait/reliable via UART, dashboard, and CLI so loss vs latency can be compared under real multi-pod load. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -38,6 +38,7 @@ go run . -port /dev/ttyUSB0 clients
|
||||
| `find-me` | 22 | Locate pod (`-client 0` master, `>0` slave via ESP-NOW) |
|
||||
| `restart` | 23 | Reboot master or slave (`-client 0` / `>0`) |
|
||||
| `log-level` | `0x1f` | Get/set master ESP-IDF log level for tag `"*"` (`-set`, `-level` 0–5); output on UART0 debug, not host UART |
|
||||
| `input-send-mode` | `0x23` | Get/set slave accel/tap ESP-NOW TX path (`-set -mode 0..3`, `-all` or `-client N`): best_effort/fast/wait/reliable |
|
||||
|
||||
`clients` requires slaves to have responded to master discover broadcasts first.
|
||||
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
pb "powerpod/gotool/pb"
|
||||
)
|
||||
|
||||
type inputSendModeAPIResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Mode uint32 `json:"mode"`
|
||||
ModeName string `json:"mode_name"`
|
||||
ClientID uint32 `json:"client_id,omitempty"`
|
||||
SlavesUpdated uint32 `json:"slaves_updated,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func inputSendModeName(mode pb.InputSendMode) string {
|
||||
switch mode {
|
||||
case pb.InputSendMode_INPUT_SEND_BEST_EFFORT:
|
||||
return "best_effort"
|
||||
case pb.InputSendMode_INPUT_SEND_FAST:
|
||||
return "fast"
|
||||
case pb.InputSendMode_INPUT_SEND_WAIT:
|
||||
return "wait"
|
||||
case pb.InputSendMode_INPUT_SEND_RELIABLE:
|
||||
return "reliable"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
func mountInputSendModeAPI(mux *http.ServeMux, link *managedSerial) {
|
||||
mux.HandleFunc("/api/input-send-mode", func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
serveInputSendModeGet(w, link)
|
||||
case http.MethodPut, http.MethodPost:
|
||||
serveInputSendModePut(w, r, link)
|
||||
default:
|
||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func serveInputSendModeGet(w http.ResponseWriter, link *managedSerial) {
|
||||
resp, err := link.InputSendMode(&pb.InputSendModeRequest{Write: false})
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusBadGateway, inputSendModeAPIResponse{Error: err.Error()})
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, inputSendModeAPIResponse{
|
||||
Success: resp.GetSuccess(),
|
||||
Mode: uint32(resp.GetMode()),
|
||||
ModeName: inputSendModeName(resp.GetMode()),
|
||||
})
|
||||
}
|
||||
|
||||
func serveInputSendModePut(w http.ResponseWriter, r *http.Request, link *managedSerial) {
|
||||
var body struct {
|
||||
Mode uint32 `json:"mode"`
|
||||
ClientID uint32 `json:"client_id"`
|
||||
AllClients bool `json:"all_clients"`
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
|
||||
writeJSON(w, http.StatusBadRequest, inputSendModeAPIResponse{Error: "invalid JSON"})
|
||||
return
|
||||
}
|
||||
if body.Mode > uint32(pb.InputSendMode_INPUT_SEND_RELIABLE) {
|
||||
writeJSON(w, http.StatusBadRequest, inputSendModeAPIResponse{Error: "mode must be 0..3"})
|
||||
return
|
||||
}
|
||||
if !body.AllClients && body.ClientID == 0 {
|
||||
// Dashboard default: apply to every registered slave.
|
||||
body.AllClients = true
|
||||
}
|
||||
|
||||
resp, err := link.InputSendMode(&pb.InputSendModeRequest{
|
||||
Write: true,
|
||||
Mode: pb.InputSendMode(body.Mode),
|
||||
ClientId: body.ClientID,
|
||||
AllClients: body.AllClients,
|
||||
})
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusBadGateway, inputSendModeAPIResponse{Error: err.Error()})
|
||||
return
|
||||
}
|
||||
status := http.StatusOK
|
||||
if !resp.GetSuccess() {
|
||||
status = http.StatusBadRequest
|
||||
}
|
||||
writeJSON(w, status, inputSendModeAPIResponse{
|
||||
Success: resp.GetSuccess(),
|
||||
Mode: uint32(resp.GetMode()),
|
||||
ModeName: inputSendModeName(resp.GetMode()),
|
||||
ClientID: resp.GetClientId(),
|
||||
SlavesUpdated: resp.GetSlavesUpdated(),
|
||||
})
|
||||
}
|
||||
@@ -102,6 +102,7 @@ func mountServeAPI(mux *http.ServeMux, link *managedSerial, hub *wsHub, streamCt
|
||||
mountBleTestAPI(mux, link)
|
||||
mountLiveStreamAPI(mux, hub)
|
||||
mountAccelStreamAPI(mux, link, hub, streamCtl)
|
||||
mountInputSendModeAPI(mux, link)
|
||||
mountTapAPI(mux, link, hub, tapCtl)
|
||||
mountTapConfigAPI(mux, link)
|
||||
mountLedRingAPI(mux, link)
|
||||
|
||||
@@ -156,7 +156,7 @@ func (m *managedSerial) TapNotifyPoll(req *pb.TapNotifyRequest) (*pb.TapNotifyRe
|
||||
|
||||
func (m *managedSerial) tapNotifyExchange(poll bool, req *pb.TapNotifyRequest) (*pb.TapNotifyResponse, error) {
|
||||
msg := &pb.UartMessage{
|
||||
Type: pb.MessageType_TAP_NOTIFY,
|
||||
Type: pb.MessageType_TAP_NOTIFY,
|
||||
Payload: &pb.UartMessage_TapNotifyRequest{TapNotifyRequest: req},
|
||||
}
|
||||
body, err := proto.Marshal(msg)
|
||||
@@ -216,7 +216,7 @@ func decodeCacheStatusPayload(payload []byte) (*pb.CacheStatusResponse, error) {
|
||||
|
||||
func (m *managedSerial) accelStreamExchange(poll bool, req *pb.AccelStreamRequest) (*pb.AccelStreamResponse, error) {
|
||||
msg := &pb.UartMessage{
|
||||
Type: pb.MessageType_ACCEL_STREAM,
|
||||
Type: pb.MessageType_ACCEL_STREAM,
|
||||
Payload: &pb.UartMessage_AccelStreamRequest{AccelStreamRequest: req},
|
||||
}
|
||||
body, err := proto.Marshal(msg)
|
||||
@@ -262,7 +262,7 @@ func (m *managedSerial) TapConfigPoll(req *pb.TapConfigRequest) (*pb.TapConfigRe
|
||||
|
||||
func (m *managedSerial) tapConfigExchange(poll bool, req *pb.TapConfigRequest) (*pb.TapConfigResponse, error) {
|
||||
msg := &pb.UartMessage{
|
||||
Type: pb.MessageType_TAP_CONFIG,
|
||||
Type: pb.MessageType_TAP_CONFIG,
|
||||
Payload: &pb.UartMessage_TapConfigRequest{TapConfigRequest: req},
|
||||
}
|
||||
body, err := proto.Marshal(msg)
|
||||
@@ -292,7 +292,7 @@ func (m *managedSerial) tapConfigExchange(poll bool, req *pb.TapConfigRequest) (
|
||||
|
||||
func (m *managedSerial) accelDeadzoneExchange(poll bool, req *pb.AccelDeadzoneRequest) (*pb.AccelDeadzoneResponse, error) {
|
||||
msg := &pb.UartMessage{
|
||||
Type: pb.MessageType_ACCEL_DEADZONE,
|
||||
Type: pb.MessageType_ACCEL_DEADZONE,
|
||||
Payload: &pb.UartMessage_AccelDeadzoneRequest{AccelDeadzoneRequest: req},
|
||||
}
|
||||
body, err := proto.Marshal(msg)
|
||||
@@ -606,6 +606,10 @@ func (m *managedSerial) SetLogLevel(write bool, level uint32) (*pb.SetLogLevelRe
|
||||
return hostSetLogLevel(m, write, level)
|
||||
}
|
||||
|
||||
func (m *managedSerial) InputSendMode(req *pb.InputSendModeRequest) (*pb.InputSendModeResponse, error) {
|
||||
return hostInputSendMode(m, req)
|
||||
}
|
||||
|
||||
func (m *managedSerial) Restart(clientID uint32) error {
|
||||
if err := hostRestart(m, clientID); err != nil {
|
||||
return err
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
|
||||
pb "powerpod/gotool/pb"
|
||||
)
|
||||
|
||||
func runInputSendModeCmd(h hostConn, args []string) error {
|
||||
fs := flag.NewFlagSet("input-send-mode", flag.ExitOnError)
|
||||
write := fs.Bool("set", false, "write mode to slave(s)")
|
||||
mode := fs.Uint("mode", 0, "0=best_effort 1=fast 2=wait 3=reliable")
|
||||
clientID := fs.Uint("client", 0, "slave client_id (required unless -all)")
|
||||
all := fs.Bool("all", false, "apply to every registered slave")
|
||||
_ = fs.Parse(args)
|
||||
|
||||
req := &pb.InputSendModeRequest{
|
||||
Write: *write,
|
||||
Mode: pb.InputSendMode(*mode),
|
||||
ClientId: uint32(*clientID),
|
||||
AllClients: *all,
|
||||
}
|
||||
if *write && !*all && *clientID == 0 {
|
||||
return fmt.Errorf("need -client N or -all when using -set")
|
||||
}
|
||||
if *write && *mode > uint(pb.InputSendMode_INPUT_SEND_RELIABLE) {
|
||||
return fmt.Errorf("mode must be 0..3")
|
||||
}
|
||||
|
||||
r, err := hostInputSendMode(h, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("input-send-mode: success=%v mode=%d (%s) client_id=%d slaves_updated=%d\n",
|
||||
r.GetSuccess(), r.GetMode(), inputSendModeName(r.GetMode()), r.GetClientId(),
|
||||
r.GetSlavesUpdated())
|
||||
if *write && !r.GetSuccess() {
|
||||
return fmt.Errorf("input-send-mode rejected")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -400,6 +400,37 @@ go run . -port /dev/ttyUSB0 log-level -set -level 3
|
||||
|
||||
Dashboard: Master card → dropdown **ESP Log-Level** with **Lesen** / **Setzen**.
|
||||
|
||||
### Input send mode (slave accel/tap ESP-NOW TX path)
|
||||
|
||||
Debug A/B for how slaves transmit `ACCEL_SAMPLE` / `TAP_EVENT`. Default on slaves is `best_effort` (0). Master remembers the last mode for GET; write pushes via ESP-NOW.
|
||||
|
||||
```http
|
||||
GET /api/input-send-mode
|
||||
PUT /api/input-send-mode
|
||||
Content-Type: application/json
|
||||
{"mode": 2, "all_clients": true}
|
||||
```
|
||||
|
||||
| `mode` | Path |
|
||||
|--------|------|
|
||||
| 0 | `best_effort` (fire-and-forget, quiet) |
|
||||
| 1 | `fast` (fire-and-forget, logs failures) |
|
||||
| 2 | `wait` (send-done + retries) |
|
||||
| 3 | `reliable` (OTA-style retries; can stall high-rate accel) |
|
||||
|
||||
```json
|
||||
{"success": true, "mode": 2, "mode_name": "wait", "slaves_updated": 2}
|
||||
```
|
||||
|
||||
**CLI:**
|
||||
|
||||
```bash
|
||||
go run . -port /dev/ttyUSB0 input-send-mode
|
||||
go run . -port /dev/ttyUSB0 input-send-mode -set -mode 2 -all
|
||||
```
|
||||
|
||||
Dashboard: ESP-NOW Slaves toolbar → **Input-Send** dropdown + **Setzen** / **Lesen**.
|
||||
|
||||
### OTA (master host upload, UART or BLE)
|
||||
|
||||
```http
|
||||
@@ -455,5 +486,6 @@ Same as external API:
|
||||
| Unicast test | `POST /api/unicast-test` |
|
||||
| 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` |
|
||||
| Input-Send mode | `GET` / `PUT /api/input-send-mode` or CLI `input-send-mode` |
|
||||
| Tap notify S/D/T | `PUT /api/clients/{id}/tap-notify` |
|
||||
| Tap receive (UI) | Live stream + tap notify; see WebSocket doc for external API |
|
||||
|
||||
+28
-1
@@ -4,8 +4,8 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
pb "powerpod/gotool/pb"
|
||||
"google.golang.org/protobuf/proto"
|
||||
pb "powerpod/gotool/pb"
|
||||
)
|
||||
|
||||
// hostConn is the UART or BLE host transport used by CLI commands.
|
||||
@@ -160,6 +160,33 @@ func hostSetLogLevel(h hostConn, write bool, level uint32) (*pb.SetLogLevelRespo
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func hostInputSendMode(h hostConn, req *pb.InputSendModeRequest) (*pb.InputSendModeResponse, error) {
|
||||
msg := &pb.UartMessage{
|
||||
Type: pb.MessageType_INPUT_SEND_MODE,
|
||||
Payload: &pb.UartMessage_InputSendModeRequest{
|
||||
InputSendModeRequest: req,
|
||||
},
|
||||
}
|
||||
body, err := proto.Marshal(msg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("encode: %w", err)
|
||||
}
|
||||
payload := append([]byte{byte(pb.MessageType_INPUT_SEND_MODE)}, body...)
|
||||
respPayload, err := h.exchangePayload(payload, "INPUT_SEND_MODE")
|
||||
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.GetInputSendModeResponse()
|
||||
if r == nil {
|
||||
return nil, fmt.Errorf("missing input_send_mode_response")
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func hostLedRing(h hostConn, req *pb.LedRingProgressRequest) (*pb.LedRingProgressResponse, error) {
|
||||
msg := &pb.UartMessage{
|
||||
Type: pb.MessageType_LED_RING,
|
||||
|
||||
+5
-2
@@ -34,7 +34,8 @@ func usage() {
|
||||
fmt.Fprintf(os.Stderr, " led-ring set LED ring progress bar (0–100%%, rgb, intensity)\n")
|
||||
fmt.Fprintf(os.Stderr, " find-me blink LED ring red/green/blue (3× each, full brightness)\n")
|
||||
fmt.Fprintf(os.Stderr, " restart reboot master or slave (ESP-NOW)\n")
|
||||
fmt.Fprintf(os.Stderr, " log-level get/set master ESP-IDF log level (global)\n\n")
|
||||
fmt.Fprintf(os.Stderr, " log-level get/set master ESP-IDF log level (global)\n")
|
||||
fmt.Fprintf(os.Stderr, " input-send-mode get/set slave accel/tap ESP-NOW send path\n\n")
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
|
||||
@@ -73,7 +74,7 @@ func main() {
|
||||
bleName: *bleName,
|
||||
settle: time.Duration(*bleSettle * float64(time.Second)),
|
||||
}, flag.Args()[1:])
|
||||
case "version", "clients", "client-info", "clients-reset-ids", "clients_reset_ids", "deadzone", "accel-deadzone", "tap-config", "tap_config", "tap-notify", "tap_notify", "cache-status", "cache_status", "accel-stream", "accel_stream", "unicast-test", "unicast_test", "echo-ping", "echo_ping", "ble-rtt", "ble_rtt", "ble-stream", "ble_stream", "led-ring", "led_ring", "find-me", "find_me", "restart", "log-level", "log_level", "ota", "ota-progress", "ota_progress":
|
||||
case "version", "clients", "client-info", "clients-reset-ids", "clients_reset_ids", "deadzone", "accel-deadzone", "tap-config", "tap_config", "tap-notify", "tap_notify", "cache-status", "cache_status", "accel-stream", "accel_stream", "unicast-test", "unicast_test", "echo-ping", "echo_ping", "ble-rtt", "ble_rtt", "ble-stream", "ble_stream", "led-ring", "led_ring", "find-me", "find_me", "restart", "log-level", "log_level", "input-send-mode", "input_send_mode", "ota", "ota-progress", "ota_progress":
|
||||
if *useBLE && *portName != "" {
|
||||
fmt.Fprintf(os.Stderr, "use either -port or -ble, not both\n")
|
||||
os.Exit(2)
|
||||
@@ -179,6 +180,8 @@ func main() {
|
||||
break
|
||||
}
|
||||
runErr = runLogLevel(sp, flag.Args()[1:])
|
||||
case "input-send-mode", "input_send_mode":
|
||||
runErr = runInputSendModeCmd(h, flag.Args()[1:])
|
||||
case "ota":
|
||||
t, ok := h.(otaTransport)
|
||||
if !ok {
|
||||
|
||||
+491
-231
File diff suppressed because it is too large
Load Diff
@@ -553,6 +553,8 @@
|
||||
<strong>Live-Stream</strong>: UART ≈ <code>CACHE_STATUS</code>-Poll (~16 ms); BLE ≈
|
||||
<code>BLE_STREAM_TICK</code>-Push. Pro Slave <strong>Accel</strong> aktiviert den ESP-NOW-Stream;
|
||||
Tap-Notify (S/D/T) steuert die Tap-Arten auf dem Slave.
|
||||
<strong>Input-Send</strong> wählt den ESP-NOW-TX-Pfad für Accel/Tap auf den Slaves
|
||||
(<code>best_effort</code> Default; <code>wait</code>/<code>reliable</code> blockieren länger).
|
||||
</p>
|
||||
<div class="px-3 pb-2 d-flex flex-wrap gap-2 align-items-center">
|
||||
<button type="button"
|
||||
@@ -564,6 +566,28 @@
|
||||
<span class="text-muted small font-monospace" x-show="isBLEHost() && state.live_stream"
|
||||
x-text="bleTickLabel()"
|
||||
title="Median Δt zwischen BLE_STREAM_TICK (esp_timestamp_us)"></span>
|
||||
<label class="text-muted small mb-0" for="input-send-mode">Input-Send:</label>
|
||||
<select id="input-send-mode" class="form-select form-select-sm"
|
||||
style="width: auto; min-width: 9rem;"
|
||||
x-model.number="inputSendMode"
|
||||
:disabled="busy || !hostUp() || !(state.clients || []).length">
|
||||
<option :value="0">best_effort</option>
|
||||
<option :value="1">fast</option>
|
||||
<option :value="2">wait</option>
|
||||
<option :value="3">reliable</option>
|
||||
</select>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm"
|
||||
@click="setInputSendMode(inputSendMode)"
|
||||
:disabled="busy || !hostUp() || !(state.clients || []).length"
|
||||
title="Modus an alle registrierten Slaves pushen">
|
||||
Setzen
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm"
|
||||
@click="readInputSendMode()"
|
||||
:disabled="busy || !hostUp()"
|
||||
title="Zuletzt gesetzten Modus vom Master lesen">
|
||||
Lesen
|
||||
</button>
|
||||
<span class="text-muted small">Tap alle Slaves:</span>
|
||||
<label class="tap-toggle"><input type="checkbox" x-model="allTapSingle" :disabled="busy"> S</label>
|
||||
<label class="tap-toggle"><input type="checkbox" x-model="allTapDouble" :disabled="busy"> D</label>
|
||||
@@ -913,6 +937,7 @@
|
||||
masterDz: 100,
|
||||
masterDzSeeded: false,
|
||||
masterLogLevel: 0,
|
||||
inputSendMode: 0,
|
||||
masterTapCfg: {
|
||||
tap_sens_thres: 5,
|
||||
max_gest_dur: 100,
|
||||
@@ -1796,6 +1821,52 @@
|
||||
this.busy = false;
|
||||
}
|
||||
},
|
||||
formatInputSendMode(mode) {
|
||||
const labels = ['best_effort', 'fast', 'wait', 'reliable'];
|
||||
if (mode == null || mode < 0 || mode > 3) return '—';
|
||||
return labels[mode];
|
||||
},
|
||||
async readInputSendMode() {
|
||||
this.busy = true;
|
||||
try {
|
||||
const r = await fetch('/api/input-send-mode');
|
||||
const data = await r.json();
|
||||
if (!r.ok || !data.success) {
|
||||
this.flash(data.error || 'Input-Send lesen fehlgeschlagen', false);
|
||||
return;
|
||||
}
|
||||
this.inputSendMode = data.mode ?? 0;
|
||||
this.flash(`Input-Send: ${data.mode_name || this.formatInputSendMode(data.mode)}`, true);
|
||||
} catch (e) {
|
||||
this.flash(String(e), false);
|
||||
} finally {
|
||||
this.busy = false;
|
||||
}
|
||||
},
|
||||
async setInputSendMode(mode) {
|
||||
this.busy = true;
|
||||
try {
|
||||
const r = await fetch('/api/input-send-mode', {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ mode, all_clients: true })
|
||||
});
|
||||
const data = await r.json();
|
||||
if (!r.ok || !data.success) {
|
||||
this.flash(data.error || 'Input-Send setzen fehlgeschlagen', false);
|
||||
return;
|
||||
}
|
||||
this.inputSendMode = data.mode ?? mode;
|
||||
this.flash(
|
||||
`Input-Send ${data.mode_name || this.formatInputSendMode(data.mode)} → ${data.slaves_updated || 0} Slaves`,
|
||||
true
|
||||
);
|
||||
} catch (e) {
|
||||
this.flash(String(e), false);
|
||||
} finally {
|
||||
this.busy = false;
|
||||
}
|
||||
},
|
||||
patchClientAccelStream(clientId, enabled) {
|
||||
const clients = (this.state.clients || []).map((c) => {
|
||||
if (c.id !== clientId) return c;
|
||||
|
||||
@@ -22,6 +22,7 @@ idf_component_register(
|
||||
"cmd/cmd_client_info.c"
|
||||
"cmd/cmd_accel_deadzone.c"
|
||||
"cmd/cmd_accel_stream.c"
|
||||
"cmd/cmd_input_send_mode.c"
|
||||
"cmd/cmd_tap_notify.c"
|
||||
"cmd/cmd_tap_config.c"
|
||||
"cmd/cmd_cache_status.c"
|
||||
|
||||
+3
-1
@@ -124,7 +124,8 @@ Schema: `proto/esp_now_messages.proto`. Encode/decode: `esp_now_proto.c`. The ES
|
||||
| `ESPNOW_UNICAST_TEST` | Master → slave | `EspNowUnicastTest` (`seq`) |
|
||||
| `ESPNOW_FIND_ME` | Master → slave | `EspNowFindMe` (`client_id` filter) — LED locate sequence |
|
||||
| `ESPNOW_RESTART` | Master → slave | `EspNowRestart` (`client_id` filter) — reboot slave |
|
||||
| `ESPNOW_ACCEL_SAMPLE` | Slave → master | `EspNowAccelSample` (`slave_id`, `x`, `y`, `z` raw LSB) — ~every 8 ms, best-effort |
|
||||
| `ESPNOW_ACCEL_SAMPLE` | Slave → master | `EspNowAccelSample` (`slave_id`, `x`, `y`, `z` raw LSB) — ~every 10 ms; TX path via `INPUT_SEND_MODE` (default best-effort) |
|
||||
| `ESPNOW_SET_INPUT_SEND_MODE` | Master → slave | `EspNowInputSendMode` (`mode` 0..3 = best_effort/fast/wait/reliable) |
|
||||
| `ESPNOW_SET_TAP_NOTIFY` | Master → slave | `EspNowTapNotify` (`client_id`, `single`, `double_tap`, `triple`) — which tap kinds to forward |
|
||||
| `ESPNOW_TAP_EVENT` | Slave → master | `EspNowTapEvent` (`client_id`, `kind`) — on BMA456 tap interrupt if notify enabled |
|
||||
| `ESPNOW_BATTERY_REPORT` | Slave → master | `EspNowBatteryReport` (`client_id`, `lipo1/2` mV) — ~every 30 s; cached in `client_registry` |
|
||||
@@ -233,6 +234,7 @@ Host and master speak nanopb-encoded `UartMessage` inside UART frames (byte 0 =
|
||||
| 22 | `FIND_ME` | Implemented (`cmd/cmd_espnow_find_me.c`) — `client_id=0` local ring, `>0` ESP-NOW to slave |
|
||||
| 23 | `RESTART` | Implemented (`cmd/cmd_restart.c`) — `client_id=0` reboot master, `>0` ESP-NOW reboot slave |
|
||||
| 25 | `ACCEL_STREAM` | Implemented — enable/disable slave ESP-NOW accel stream to master |
|
||||
| 35 | `INPUT_SEND_MODE` | Implemented — get/set slave accel/tap ESP-NOW send path (best_effort/fast/wait/reliable) |
|
||||
| 27 | `TAP_NOTIFY` | Implemented (`cmd/cmd_tap_notify.c`) — get/set which tap kinds notify via ESP-NOW |
|
||||
| 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) |
|
||||
|
||||
@@ -63,6 +63,10 @@ static const char *message_type_name(uint16_t id) {
|
||||
return "SET_LOG_LEVEL";
|
||||
case alox_MessageType_TAP_CONFIG:
|
||||
return "TAP_CONFIG";
|
||||
case alox_MessageType_CLIENT_ID_MAP_RESET:
|
||||
return "CLIENT_ID_MAP_RESET";
|
||||
case alox_MessageType_INPUT_SEND_MODE:
|
||||
return "INPUT_SEND_MODE";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
#include "cmd_input_send_mode.h"
|
||||
#include "client_registry.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_now_comm.h"
|
||||
#include "uart_cmd.h"
|
||||
|
||||
static const char *TAG = "[INPUT_SEND]";
|
||||
|
||||
/** Last mode pushed from host (GET returns this; slaves may lag until re-push). */
|
||||
static alox_InputSendMode s_mode = alox_InputSendMode_INPUT_SEND_BEST_EFFORT;
|
||||
|
||||
static bool valid_mode(alox_InputSendMode mode) {
|
||||
return mode <= alox_InputSendMode_INPUT_SEND_RELIABLE;
|
||||
}
|
||||
|
||||
static void reply(bool success, alox_InputSendMode mode, uint32_t client_id,
|
||||
uint32_t slaves_updated) {
|
||||
alox_UartMessage response;
|
||||
uart_cmd_init_response(&response, alox_MessageType_INPUT_SEND_MODE,
|
||||
alox_UartMessage_input_send_mode_response_tag);
|
||||
response.payload.input_send_mode_response.success = success;
|
||||
response.payload.input_send_mode_response.mode = mode;
|
||||
response.payload.input_send_mode_response.client_id = client_id;
|
||||
response.payload.input_send_mode_response.slaves_updated = slaves_updated;
|
||||
uart_cmd_send(&response, TAG);
|
||||
}
|
||||
|
||||
static esp_err_t push_mode_to_slave(const client_info_t *client,
|
||||
alox_InputSendMode mode) {
|
||||
if (client == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
return esp_now_comm_send_input_send_mode(client->mac, client->id,
|
||||
(uint32_t)mode);
|
||||
}
|
||||
|
||||
static void handle_input_send_mode(const uint8_t *data, size_t len) {
|
||||
alox_UartMessage uart_msg;
|
||||
alox_InputSendModeRequest req = alox_InputSendModeRequest_init_zero;
|
||||
|
||||
if (len > 0) {
|
||||
if (uart_cmd_decode(data, len, &uart_msg) != ESP_OK) {
|
||||
ESP_LOGW(TAG, "decode failed");
|
||||
reply(false, s_mode, 0, 0);
|
||||
return;
|
||||
}
|
||||
const alox_InputSendModeRequest *req_ptr =
|
||||
UART_CMD_REQ(&uart_msg, alox_UartMessage_input_send_mode_request_tag,
|
||||
input_send_mode_request);
|
||||
if (req_ptr == NULL) {
|
||||
ESP_LOGW(TAG, "missing input_send_mode_request");
|
||||
reply(false, s_mode, 0, 0);
|
||||
return;
|
||||
}
|
||||
req = *req_ptr;
|
||||
}
|
||||
|
||||
if (req.write) {
|
||||
if (!valid_mode(req.mode)) {
|
||||
ESP_LOGW(TAG, "invalid mode %lu", (unsigned long)req.mode);
|
||||
reply(false, s_mode, req.client_id, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.all_clients) {
|
||||
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 (push_mode_to_slave(client, req.mode) == ESP_OK) {
|
||||
sent++;
|
||||
}
|
||||
}
|
||||
s_mode = req.mode;
|
||||
ESP_LOGI(TAG, "input send mode %lu for %u slaves",
|
||||
(unsigned long)req.mode, (unsigned)sent);
|
||||
reply(sent > 0 || client_registry_count() == 0, req.mode, 0, sent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.client_id == 0) {
|
||||
ESP_LOGW(TAG, "client_id required (or all_clients)");
|
||||
reply(false, req.mode, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
const client_info_t *client = client_registry_find_by_id(req.client_id);
|
||||
if (client == NULL) {
|
||||
ESP_LOGW(TAG, "client id %lu not found", (unsigned long)req.client_id);
|
||||
reply(false, req.mode, req.client_id, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
esp_err_t err = push_mode_to_slave(client, req.mode);
|
||||
if (err == ESP_OK) {
|
||||
s_mode = req.mode;
|
||||
}
|
||||
reply(err == ESP_OK, req.mode, req.client_id, err == ESP_OK ? 1u : 0u);
|
||||
return;
|
||||
}
|
||||
|
||||
reply(true, s_mode, 0, 0);
|
||||
}
|
||||
|
||||
void cmd_input_send_mode_register(void) {
|
||||
uart_cmd_register(alox_MessageType_INPUT_SEND_MODE, handle_input_send_mode);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef CMD_INPUT_SEND_MODE_H
|
||||
#define CMD_INPUT_SEND_MODE_H
|
||||
|
||||
void cmd_input_send_mode_register(void);
|
||||
|
||||
#endif
|
||||
@@ -13,6 +13,10 @@ esp_err_t esp_now_comm_init(const app_config_t *config);
|
||||
esp_err_t esp_now_comm_send_accel_stream(const uint8_t mac[CLIENT_MAC_LEN],
|
||||
uint32_t client_id, bool enable);
|
||||
|
||||
/** Master: set accel/tap ESP-NOW send path on one slave (InputSendMode). */
|
||||
esp_err_t esp_now_comm_send_input_send_mode(const uint8_t mac[CLIENT_MAC_LEN],
|
||||
uint32_t client_id, uint32_t mode);
|
||||
|
||||
/** Master: configure tap notify flags on one slave. */
|
||||
esp_err_t esp_now_comm_send_tap_notify(const uint8_t mac[CLIENT_MAC_LEN],
|
||||
uint32_t client_id, bool single,
|
||||
|
||||
@@ -37,6 +37,16 @@ static esp_err_t send_accel_stream(const uint8_t *dest_mac, uint32_t client_id,
|
||||
return esp_now_core_send(dest_mac, &msg);
|
||||
}
|
||||
|
||||
static esp_err_t send_input_send_mode(const uint8_t *dest_mac,
|
||||
uint32_t client_id, uint32_t mode) {
|
||||
alox_EspNowMessage msg = alox_EspNowMessage_init_zero;
|
||||
msg.type = alox_EspNowMessageType_ESPNOW_SET_INPUT_SEND_MODE;
|
||||
msg.which_payload = alox_EspNowMessage_input_send_mode_tag;
|
||||
msg.payload.input_send_mode.client_id = client_id;
|
||||
msg.payload.input_send_mode.mode = mode;
|
||||
return esp_now_core_send(dest_mac, &msg);
|
||||
}
|
||||
|
||||
static esp_err_t send_accel_deadzone(const uint8_t *dest_mac, uint32_t client_id,
|
||||
uint32_t deadzone) {
|
||||
alox_EspNowMessage msg = alox_EspNowMessage_init_zero;
|
||||
@@ -446,6 +456,24 @@ esp_err_t esp_now_comm_send_accel_stream(const uint8_t mac[CLIENT_MAC_LEN],
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_now_comm_send_input_send_mode(const uint8_t mac[CLIENT_MAC_LEN],
|
||||
uint32_t client_id, uint32_t mode) {
|
||||
if (mac == NULL || !esp_now_core_is_master()) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
char mac_str[18];
|
||||
esp_now_core_mac_to_str(mac, mac_str, sizeof(mac_str));
|
||||
esp_err_t err = send_input_send_mode(mac, client_id, mode);
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "unicast SET_INPUT_SEND_MODE to %s: mode=%lu client_id=%lu",
|
||||
mac_str, (unsigned long)mode, (unsigned long)client_id);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "unicast SET_INPUT_SEND_MODE to %s failed: %s", mac_str,
|
||||
esp_err_to_name(err));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_now_comm_send_tap_notify(const uint8_t mac[CLIENT_MAC_LEN],
|
||||
uint32_t client_id, bool single,
|
||||
bool double_tap, bool triple) {
|
||||
|
||||
+66
-7
@@ -24,9 +24,9 @@
|
||||
/** While master or slave OTA is in progress (discover may be sparse). */
|
||||
#define SLAVE_MASTER_OTA_GRACE_MS 300000u
|
||||
/**
|
||||
* Best-effort gaming input cadence (loss OK; send_best_effort).
|
||||
* Must be >= one FreeRTOS tick (CONFIG_FREERTOS_HZ=100 → 10 ms); shorter
|
||||
* values become 0 ticks and assert in vTaskDelayUntil.
|
||||
* Accel stream cadence. TX path is selectable (INPUT_SEND_MODE; default
|
||||
* best_effort). Must be >= one FreeRTOS tick (CONFIG_FREERTOS_HZ=100 → 10 ms);
|
||||
* shorter values become 0 ticks and assert in vTaskDelayUntil.
|
||||
*/
|
||||
#define ESPNOW_ACCEL_INTERVAL_MS 10
|
||||
#define ESPNOW_BATTERY_INTERVAL_MS 30000
|
||||
@@ -40,6 +40,9 @@ static bool s_accel_stream_enabled;
|
||||
static bool s_tap_notify_single;
|
||||
static bool s_tap_notify_double;
|
||||
static bool s_tap_notify_triple;
|
||||
/** Accel/tap TX path; default matches historical best-effort gaming input. */
|
||||
static uint32_t s_input_send_mode =
|
||||
(uint32_t)alox_InputSendMode_INPUT_SEND_BEST_EFFORT;
|
||||
static uint8_t s_master_mac[ESP_NOW_ETH_ALEN];
|
||||
static uint32_t s_last_discover_ms;
|
||||
/** Logical id assigned by current/last master (0 = unbound). */
|
||||
@@ -161,6 +164,21 @@ static void send_presence(const uint8_t *dest_mac, alox_EspNowMessageType type)
|
||||
esp_now_core_send(dest_mac, &msg);
|
||||
}
|
||||
|
||||
static esp_err_t send_input_message(const uint8_t *dest_mac,
|
||||
const alox_EspNowMessage *msg) {
|
||||
switch (s_input_send_mode) {
|
||||
case (uint32_t)alox_InputSendMode_INPUT_SEND_FAST:
|
||||
return esp_now_core_send_fast(dest_mac, msg);
|
||||
case (uint32_t)alox_InputSendMode_INPUT_SEND_WAIT:
|
||||
return esp_now_core_send_wait(dest_mac, msg);
|
||||
case (uint32_t)alox_InputSendMode_INPUT_SEND_RELIABLE:
|
||||
return esp_now_core_send_reliable(dest_mac, msg);
|
||||
case (uint32_t)alox_InputSendMode_INPUT_SEND_BEST_EFFORT:
|
||||
default:
|
||||
return esp_now_core_send_best_effort(dest_mac, msg);
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t send_accel_sample(const uint8_t *dest_mac, uint32_t slave_id,
|
||||
int16_t x, int16_t y, int16_t z) {
|
||||
alox_EspNowMessage msg = alox_EspNowMessage_init_zero;
|
||||
@@ -170,8 +188,7 @@ static esp_err_t send_accel_sample(const uint8_t *dest_mac, uint32_t slave_id,
|
||||
msg.payload.accel_sample.x = x;
|
||||
msg.payload.accel_sample.y = y;
|
||||
msg.payload.accel_sample.z = z;
|
||||
/* Fire-and-forget: controller input prefers low latency over delivery. */
|
||||
return esp_now_core_send_best_effort(dest_mac, &msg);
|
||||
return send_input_message(dest_mac, &msg);
|
||||
}
|
||||
|
||||
static esp_err_t send_tap_event(const uint8_t *dest_mac, uint32_t slave_id,
|
||||
@@ -181,7 +198,7 @@ static esp_err_t send_tap_event(const uint8_t *dest_mac, uint32_t slave_id,
|
||||
msg.which_payload = alox_EspNowMessage_tap_event_tag;
|
||||
msg.payload.tap_event.slave_id = slave_id;
|
||||
msg.payload.tap_event.kind = kind;
|
||||
return esp_now_core_send_best_effort(dest_mac, &msg);
|
||||
return send_input_message(dest_mac, &msg);
|
||||
}
|
||||
|
||||
static esp_err_t send_battery_report(const uint8_t *dest_mac,
|
||||
@@ -429,6 +446,43 @@ static void handle_accel_stream(const uint8_t *master_mac,
|
||||
cfg->enable ? "on" : "off", mac_str, (unsigned long)my_client_id());
|
||||
}
|
||||
|
||||
static const char *input_send_mode_name(uint32_t mode) {
|
||||
switch (mode) {
|
||||
case (uint32_t)alox_InputSendMode_INPUT_SEND_BEST_EFFORT:
|
||||
return "best_effort";
|
||||
case (uint32_t)alox_InputSendMode_INPUT_SEND_FAST:
|
||||
return "fast";
|
||||
case (uint32_t)alox_InputSendMode_INPUT_SEND_WAIT:
|
||||
return "wait";
|
||||
case (uint32_t)alox_InputSendMode_INPUT_SEND_RELIABLE:
|
||||
return "reliable";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_input_send_mode(const uint8_t *master_mac,
|
||||
const alox_EspNowInputSendMode *cfg) {
|
||||
if (!client_id_matches(cfg->client_id)) {
|
||||
return;
|
||||
}
|
||||
if (s_joined && !esp_now_core_mac_equal(master_mac, s_master_mac)) {
|
||||
return;
|
||||
}
|
||||
if (cfg->mode > (uint32_t)alox_InputSendMode_INPUT_SEND_RELIABLE) {
|
||||
ESP_LOGW(TAG, "input send mode %lu invalid (id=%lu)",
|
||||
(unsigned long)cfg->mode, (unsigned long)my_client_id());
|
||||
return;
|
||||
}
|
||||
s_input_send_mode = cfg->mode;
|
||||
char mac_str[18];
|
||||
esp_now_core_mac_to_str(master_mac, mac_str, sizeof(mac_str));
|
||||
ESP_LOGI(TAG, "input send mode %s (%lu) from master %s (id=%lu)",
|
||||
input_send_mode_name(s_input_send_mode),
|
||||
(unsigned long)s_input_send_mode, mac_str,
|
||||
(unsigned long)my_client_id());
|
||||
}
|
||||
|
||||
static void handle_tap_notify(const uint8_t *master_mac,
|
||||
const alox_EspNowTapNotify *cfg) {
|
||||
if (!client_id_matches(cfg->client_id)) {
|
||||
@@ -585,7 +639,7 @@ static void check_master_timeout(void) {
|
||||
static void accel_stream_task(void *param) {
|
||||
(void)param;
|
||||
|
||||
ESP_LOGI(TAG, "accel stream task (interval %u ms, best-effort)",
|
||||
ESP_LOGI(TAG, "accel stream task (interval %u ms, mode selectable)",
|
||||
(unsigned)ESPNOW_ACCEL_INTERVAL_MS);
|
||||
|
||||
TickType_t last_wake = xTaskGetTickCount();
|
||||
@@ -733,6 +787,11 @@ void esp_now_slave_on_recv(const esp_now_recv_info_t *info, const uint8_t *data,
|
||||
handle_tap_notify(info->src_addr, &msg.payload.tap_notify);
|
||||
}
|
||||
break;
|
||||
case alox_EspNowMessage_input_send_mode_tag:
|
||||
if (from_joined_master(info->src_addr)) {
|
||||
handle_input_send_mode(info->src_addr, &msg.payload.input_send_mode);
|
||||
}
|
||||
break;
|
||||
case alox_EspNowMessage_battery_query_tag:
|
||||
if (from_joined_master(info->src_addr)) {
|
||||
handle_battery_query(info->src_addr, &msg.payload.battery_query);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "cmd_handler.h"
|
||||
#include "cmd_accel_deadzone.h"
|
||||
#include "cmd_accel_stream.h"
|
||||
#include "cmd_input_send_mode.h"
|
||||
#include "cmd_tap_notify.h"
|
||||
#include "cmd_tap_config.h"
|
||||
#include "cmd_cache_status.h"
|
||||
@@ -221,6 +222,7 @@ void app_main(void) {
|
||||
cmd_client_info_register();
|
||||
cmd_accel_deadzone_register();
|
||||
cmd_accel_stream_register();
|
||||
cmd_input_send_mode_register();
|
||||
cmd_tap_notify_register();
|
||||
cmd_tap_config_register();
|
||||
cmd_cache_status_register();
|
||||
|
||||
@@ -54,6 +54,9 @@ PB_BIND(alox_EspNowTapConfig, alox_EspNowTapConfig, AUTO)
|
||||
PB_BIND(alox_EspNowTapEvent, alox_EspNowTapEvent, AUTO)
|
||||
|
||||
|
||||
PB_BIND(alox_EspNowInputSendMode, alox_EspNowInputSendMode, AUTO)
|
||||
|
||||
|
||||
PB_BIND(alox_EspNowBatteryReport, alox_EspNowBatteryReport, AUTO)
|
||||
|
||||
|
||||
|
||||
@@ -36,7 +36,9 @@ typedef enum _alox_EspNowMessageType {
|
||||
/* * Master → slave: assigned logical client id after join/presence. */
|
||||
alox_EspNowMessageType_ESPNOW_ASSIGN_ID = 22,
|
||||
/* * Master → slave: forget persisted master/id binding (debug reset). */
|
||||
alox_EspNowMessageType_ESPNOW_CLEAR_ID_BINDING = 23
|
||||
alox_EspNowMessageType_ESPNOW_CLEAR_ID_BINDING = 23,
|
||||
/* * Master → slave: accel/tap ESP-NOW send path (best_effort/fast/wait/reliable). */
|
||||
alox_EspNowMessageType_ESPNOW_SET_INPUT_SEND_MODE = 24
|
||||
} alox_EspNowMessageType;
|
||||
|
||||
/* Struct definitions */
|
||||
@@ -147,6 +149,14 @@ typedef struct _alox_EspNowTapEvent {
|
||||
uint32_t kind;
|
||||
} alox_EspNowTapEvent;
|
||||
|
||||
/* *
|
||||
Master → slave: which esp_now_core_send_* path to use for ACCEL_SAMPLE / TAP_EVENT.
|
||||
Values match uart InputSendMode (0=best_effort … 3=reliable). */
|
||||
typedef struct _alox_EspNowInputSendMode {
|
||||
uint32_t client_id; /* 0 = all slaves; otherwise only matching slave_id applies */
|
||||
uint32_t mode;
|
||||
} alox_EspNowInputSendMode;
|
||||
|
||||
/* * Slave → master: LiPo voltages (periodic ~30 s and on query). */
|
||||
typedef struct _alox_EspNowBatteryReport {
|
||||
uint32_t client_id;
|
||||
@@ -221,6 +231,7 @@ typedef struct _alox_EspNowMessage {
|
||||
alox_EspNowTapConfig tap_config;
|
||||
alox_EspNowAssignId assign_id;
|
||||
alox_EspNowClearIdBinding clear_id_binding;
|
||||
alox_EspNowInputSendMode input_send_mode;
|
||||
} payload;
|
||||
} alox_EspNowMessage;
|
||||
|
||||
@@ -231,8 +242,9 @@ extern "C" {
|
||||
|
||||
/* Helper constants for enums */
|
||||
#define _alox_EspNowMessageType_MIN alox_EspNowMessageType_ESPNOW_UNKNOWN
|
||||
#define _alox_EspNowMessageType_MAX alox_EspNowMessageType_ESPNOW_CLEAR_ID_BINDING
|
||||
#define _alox_EspNowMessageType_ARRAYSIZE ((alox_EspNowMessageType)(alox_EspNowMessageType_ESPNOW_CLEAR_ID_BINDING+1))
|
||||
#define _alox_EspNowMessageType_MAX alox_EspNowMessageType_ESPNOW_SET_INPUT_SEND_MODE
|
||||
#define _alox_EspNowMessageType_ARRAYSIZE ((alox_EspNowMessageType)(alox_EspNowMessageType_ESPNOW_SET_INPUT_SEND_MODE+1))
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -276,6 +288,7 @@ extern "C" {
|
||||
#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_EspNowInputSendMode_init_default {0, 0}
|
||||
#define alox_EspNowBatteryReport_init_default {0, 0, 0, 0, 0}
|
||||
#define alox_EspNowLedRing_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define alox_EspNowOtaStart_init_default {0}
|
||||
@@ -299,6 +312,7 @@ extern "C" {
|
||||
#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_EspNowInputSendMode_init_zero {0, 0}
|
||||
#define alox_EspNowBatteryReport_init_zero {0, 0, 0, 0, 0}
|
||||
#define alox_EspNowLedRing_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define alox_EspNowOtaStart_init_zero {0}
|
||||
@@ -349,6 +363,8 @@ extern "C" {
|
||||
#define alox_EspNowTapConfig_enable_triple_tag 10
|
||||
#define alox_EspNowTapEvent_slave_id_tag 1
|
||||
#define alox_EspNowTapEvent_kind_tag 2
|
||||
#define alox_EspNowInputSendMode_client_id_tag 1
|
||||
#define alox_EspNowInputSendMode_mode_tag 2
|
||||
#define alox_EspNowBatteryReport_client_id_tag 1
|
||||
#define alox_EspNowBatteryReport_lipo1_valid_tag 2
|
||||
#define alox_EspNowBatteryReport_lipo2_valid_tag 3
|
||||
@@ -394,6 +410,7 @@ extern "C" {
|
||||
#define alox_EspNowMessage_tap_config_tag 22
|
||||
#define alox_EspNowMessage_assign_id_tag 23
|
||||
#define alox_EspNowMessage_clear_id_binding_tag 24
|
||||
#define alox_EspNowMessage_input_send_mode_tag 25
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define alox_EspNowUnicastTest_FIELDLIST(X, a) \
|
||||
@@ -502,6 +519,12 @@ X(a, STATIC, SINGULAR, UINT32, kind, 2)
|
||||
#define alox_EspNowTapEvent_CALLBACK NULL
|
||||
#define alox_EspNowTapEvent_DEFAULT NULL
|
||||
|
||||
#define alox_EspNowInputSendMode_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, client_id, 1) \
|
||||
X(a, STATIC, SINGULAR, UINT32, mode, 2)
|
||||
#define alox_EspNowInputSendMode_CALLBACK NULL
|
||||
#define alox_EspNowInputSendMode_DEFAULT NULL
|
||||
|
||||
#define alox_EspNowBatteryReport_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, client_id, 1) \
|
||||
X(a, STATIC, SINGULAR, BOOL, lipo1_valid, 2) \
|
||||
@@ -572,7 +595,8 @@ 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,tap_config,payload.tap_config), 22) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,assign_id,payload.assign_id), 23) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,clear_id_binding,payload.clear_id_binding), 24)
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,clear_id_binding,payload.clear_id_binding), 24) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,input_send_mode,payload.input_send_mode), 25)
|
||||
#define alox_EspNowMessage_CALLBACK NULL
|
||||
#define alox_EspNowMessage_DEFAULT NULL
|
||||
#define alox_EspNowMessage_payload_discover_MSGTYPE alox_EspNowDiscover
|
||||
@@ -598,6 +622,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload,clear_id_binding,payload.clear_id_bi
|
||||
#define alox_EspNowMessage_payload_tap_config_MSGTYPE alox_EspNowTapConfig
|
||||
#define alox_EspNowMessage_payload_assign_id_MSGTYPE alox_EspNowAssignId
|
||||
#define alox_EspNowMessage_payload_clear_id_binding_MSGTYPE alox_EspNowClearIdBinding
|
||||
#define alox_EspNowMessage_payload_input_send_mode_MSGTYPE alox_EspNowInputSendMode
|
||||
|
||||
extern const pb_msgdesc_t alox_EspNowUnicastTest_msg;
|
||||
extern const pb_msgdesc_t alox_EspNowEchoPing_msg;
|
||||
@@ -615,6 +640,7 @@ extern const pb_msgdesc_t alox_EspNowBatteryQuery_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_EspNowInputSendMode_msg;
|
||||
extern const pb_msgdesc_t alox_EspNowBatteryReport_msg;
|
||||
extern const pb_msgdesc_t alox_EspNowLedRing_msg;
|
||||
extern const pb_msgdesc_t alox_EspNowOtaStart_msg;
|
||||
@@ -640,6 +666,7 @@ extern const pb_msgdesc_t alox_EspNowMessage_msg;
|
||||
#define alox_EspNowTapNotify_fields &alox_EspNowTapNotify_msg
|
||||
#define alox_EspNowTapConfig_fields &alox_EspNowTapConfig_msg
|
||||
#define alox_EspNowTapEvent_fields &alox_EspNowTapEvent_msg
|
||||
#define alox_EspNowInputSendMode_fields &alox_EspNowInputSendMode_msg
|
||||
#define alox_EspNowBatteryReport_fields &alox_EspNowBatteryReport_msg
|
||||
#define alox_EspNowLedRing_fields &alox_EspNowLedRing_msg
|
||||
#define alox_EspNowOtaStart_fields &alox_EspNowOtaStart_msg
|
||||
@@ -663,6 +690,7 @@ extern const pb_msgdesc_t alox_EspNowMessage_msg;
|
||||
#define alox_EspNowEchoPing_size 22
|
||||
#define alox_EspNowEchoPong_size 22
|
||||
#define alox_EspNowFindMe_size 6
|
||||
#define alox_EspNowInputSendMode_size 12
|
||||
#define alox_EspNowLedRing_size 60
|
||||
#define alox_EspNowOtaEnd_size 0
|
||||
#define alox_EspNowOtaPayload_size 209
|
||||
|
||||
@@ -31,6 +31,8 @@ enum EspNowMessageType {
|
||||
ESPNOW_ASSIGN_ID = 22;
|
||||
/** Master → slave: forget persisted master/id binding (debug reset). */
|
||||
ESPNOW_CLEAR_ID_BINDING = 23;
|
||||
/** Master → slave: accel/tap ESP-NOW send path (best_effort/fast/wait/reliable). */
|
||||
ESPNOW_SET_INPUT_SEND_MODE = 24;
|
||||
}
|
||||
|
||||
message EspNowUnicastTest {
|
||||
@@ -138,6 +140,15 @@ message EspNowTapEvent {
|
||||
uint32 kind = 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Master → slave: which esp_now_core_send_* path to use for ACCEL_SAMPLE / TAP_EVENT.
|
||||
* Values match uart InputSendMode (0=best_effort … 3=reliable).
|
||||
*/
|
||||
message EspNowInputSendMode {
|
||||
uint32 client_id = 1; // 0 = all slaves; otherwise only matching slave_id applies
|
||||
uint32 mode = 2;
|
||||
}
|
||||
|
||||
/** Slave → master: LiPo voltages (periodic ~30 s and on query). */
|
||||
message EspNowBatteryReport {
|
||||
uint32 client_id = 1;
|
||||
@@ -208,5 +219,6 @@ message EspNowMessage {
|
||||
EspNowTapConfig tap_config = 22;
|
||||
EspNowAssignId assign_id = 23;
|
||||
EspNowClearIdBinding clear_id_binding = 24;
|
||||
EspNowInputSendMode input_send_mode = 25;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,12 @@ PB_BIND(alox_AccelStreamRequest, alox_AccelStreamRequest, AUTO)
|
||||
PB_BIND(alox_AccelStreamResponse, alox_AccelStreamResponse, AUTO)
|
||||
|
||||
|
||||
PB_BIND(alox_InputSendModeRequest, alox_InputSendModeRequest, AUTO)
|
||||
|
||||
|
||||
PB_BIND(alox_InputSendModeResponse, alox_InputSendModeResponse, AUTO)
|
||||
|
||||
|
||||
PB_BIND(alox_BatteryStatusRequest, alox_BatteryStatusRequest, AUTO)
|
||||
|
||||
|
||||
@@ -158,3 +164,5 @@ PB_BIND(alox_OtaSlaveProgressResponse, alox_OtaSlaveProgressResponse, 2)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -44,9 +44,23 @@ typedef enum _alox_MessageType {
|
||||
/* *
|
||||
Host → device: clear master client-id NVS map + live registry (and notify
|
||||
online slaves), or on a slave clear local master/id binding only. */
|
||||
alox_MessageType_CLIENT_ID_MAP_RESET = 34
|
||||
alox_MessageType_CLIENT_ID_MAP_RESET = 34,
|
||||
/* *
|
||||
Host → master: get/set slave ESP-NOW send path for accel/tap
|
||||
(best_effort / fast / wait / reliable). */
|
||||
alox_MessageType_INPUT_SEND_MODE = 35
|
||||
} alox_MessageType;
|
||||
|
||||
/* *
|
||||
Slave ESP-NOW TX path for ACCEL_SAMPLE / TAP_EVENT (debug A/B).
|
||||
Maps 1:1 to esp_now_core_send_*. */
|
||||
typedef enum _alox_InputSendMode {
|
||||
alox_InputSendMode_INPUT_SEND_BEST_EFFORT = 0,
|
||||
alox_InputSendMode_INPUT_SEND_FAST = 1,
|
||||
alox_InputSendMode_INPUT_SEND_WAIT = 2,
|
||||
alox_InputSendMode_INPUT_SEND_RELIABLE = 3
|
||||
} alox_InputSendMode;
|
||||
|
||||
typedef enum _alox_TapKind {
|
||||
alox_TapKind_TAP_NONE = 0,
|
||||
alox_TapKind_TAP_SINGLE = 1,
|
||||
@@ -136,6 +150,23 @@ typedef struct _alox_AccelStreamResponse {
|
||||
uint32_t slaves_updated;
|
||||
} alox_AccelStreamResponse;
|
||||
|
||||
/* Host → master: get/set input send mode on slaves.
|
||||
write=false: return last mode remembered on master (client_id ignored).
|
||||
write=true: push mode via ESP-NOW (all_clients or one client_id). */
|
||||
typedef struct _alox_InputSendModeRequest {
|
||||
bool write;
|
||||
alox_InputSendMode mode;
|
||||
uint32_t client_id;
|
||||
bool all_clients;
|
||||
} alox_InputSendModeRequest;
|
||||
|
||||
typedef struct _alox_InputSendModeResponse {
|
||||
bool success;
|
||||
alox_InputSendMode mode;
|
||||
uint32_t client_id;
|
||||
uint32_t slaves_updated;
|
||||
} alox_InputSendModeResponse;
|
||||
|
||||
/* * Host → master: read LiPo ADC voltages (master local and/or slaves via ESP-NOW). */
|
||||
typedef struct _alox_BatteryStatusRequest {
|
||||
/* * 0 = master only; >0 = one slave; ignored when all_clients */
|
||||
@@ -380,7 +411,7 @@ typedef struct _alox_TapConfigResponse {
|
||||
bool enable_triple;
|
||||
} alox_TapConfigResponse;
|
||||
|
||||
/* Host → device: begin UART OTA (erase inactive OTA slot; device replies OTA_STATUS). */
|
||||
/* Host → device: begin host OTA over UART or BLE (erase inactive OTA slot; device replies OTA_STATUS). */
|
||||
typedef struct _alox_OtaStartPayload {
|
||||
uint32_t total_size;
|
||||
} alox_OtaStartPayload;
|
||||
@@ -471,6 +502,8 @@ typedef struct _alox_UartMessage {
|
||||
alox_BleStreamTick ble_stream_tick;
|
||||
alox_ClientIdMapResetRequest client_id_map_reset_request;
|
||||
alox_ClientIdMapResetResponse client_id_map_reset_response;
|
||||
alox_InputSendModeRequest input_send_mode_request;
|
||||
alox_InputSendModeResponse input_send_mode_response;
|
||||
} payload;
|
||||
} alox_UartMessage;
|
||||
|
||||
@@ -481,8 +514,12 @@ extern "C" {
|
||||
|
||||
/* Helper constants for enums */
|
||||
#define _alox_MessageType_MIN alox_MessageType_UNKNOWN
|
||||
#define _alox_MessageType_MAX alox_MessageType_CLIENT_ID_MAP_RESET
|
||||
#define _alox_MessageType_ARRAYSIZE ((alox_MessageType)(alox_MessageType_CLIENT_ID_MAP_RESET+1))
|
||||
#define _alox_MessageType_MAX alox_MessageType_INPUT_SEND_MODE
|
||||
#define _alox_MessageType_ARRAYSIZE ((alox_MessageType)(alox_MessageType_INPUT_SEND_MODE+1))
|
||||
|
||||
#define _alox_InputSendMode_MIN alox_InputSendMode_INPUT_SEND_BEST_EFFORT
|
||||
#define _alox_InputSendMode_MAX alox_InputSendMode_INPUT_SEND_RELIABLE
|
||||
#define _alox_InputSendMode_ARRAYSIZE ((alox_InputSendMode)(alox_InputSendMode_INPUT_SEND_RELIABLE+1))
|
||||
|
||||
#define _alox_TapKind_MIN alox_TapKind_TAP_NONE
|
||||
#define _alox_TapKind_MAX alox_TapKind_TAP_TRIPLE
|
||||
@@ -501,6 +538,10 @@ extern "C" {
|
||||
|
||||
|
||||
|
||||
#define alox_InputSendModeRequest_mode_ENUMTYPE alox_InputSendMode
|
||||
|
||||
#define alox_InputSendModeResponse_mode_ENUMTYPE alox_InputSendMode
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -554,6 +595,8 @@ extern "C" {
|
||||
#define alox_AccelDeadzoneResponse_init_default {0, 0, 0, 0}
|
||||
#define alox_AccelStreamRequest_init_default {0, 0, 0, 0, 0}
|
||||
#define alox_AccelStreamResponse_init_default {0, 0, 0, 0}
|
||||
#define alox_InputSendModeRequest_init_default {0, _alox_InputSendMode_MIN, 0, 0}
|
||||
#define alox_InputSendModeResponse_init_default {0, _alox_InputSendMode_MIN, 0, 0}
|
||||
#define alox_BatteryStatusRequest_init_default {0, 0}
|
||||
#define alox_LipoReading_init_default {0, 0}
|
||||
#define alox_BatterySample_init_default {0, false, alox_LipoReading_init_default, false, alox_LipoReading_init_default, 0}
|
||||
@@ -603,6 +646,8 @@ extern "C" {
|
||||
#define alox_AccelDeadzoneResponse_init_zero {0, 0, 0, 0}
|
||||
#define alox_AccelStreamRequest_init_zero {0, 0, 0, 0, 0}
|
||||
#define alox_AccelStreamResponse_init_zero {0, 0, 0, 0}
|
||||
#define alox_InputSendModeRequest_init_zero {0, _alox_InputSendMode_MIN, 0, 0}
|
||||
#define alox_InputSendModeResponse_init_zero {0, _alox_InputSendMode_MIN, 0, 0}
|
||||
#define alox_BatteryStatusRequest_init_zero {0, 0}
|
||||
#define alox_LipoReading_init_zero {0, 0}
|
||||
#define alox_BatterySample_init_zero {0, false, alox_LipoReading_init_zero, false, alox_LipoReading_init_zero, 0}
|
||||
@@ -680,6 +725,14 @@ extern "C" {
|
||||
#define alox_AccelStreamResponse_client_id_tag 2
|
||||
#define alox_AccelStreamResponse_success_tag 3
|
||||
#define alox_AccelStreamResponse_slaves_updated_tag 4
|
||||
#define alox_InputSendModeRequest_write_tag 1
|
||||
#define alox_InputSendModeRequest_mode_tag 2
|
||||
#define alox_InputSendModeRequest_client_id_tag 3
|
||||
#define alox_InputSendModeRequest_all_clients_tag 4
|
||||
#define alox_InputSendModeResponse_success_tag 1
|
||||
#define alox_InputSendModeResponse_mode_tag 2
|
||||
#define alox_InputSendModeResponse_client_id_tag 3
|
||||
#define alox_InputSendModeResponse_slaves_updated_tag 4
|
||||
#define alox_BatteryStatusRequest_client_id_tag 1
|
||||
#define alox_BatteryStatusRequest_all_clients_tag 2
|
||||
#define alox_LipoReading_valid_tag 1
|
||||
@@ -846,6 +899,8 @@ extern "C" {
|
||||
#define alox_UartMessage_ble_stream_tick_tag 41
|
||||
#define alox_UartMessage_client_id_map_reset_request_tag 42
|
||||
#define alox_UartMessage_client_id_map_reset_response_tag 43
|
||||
#define alox_UartMessage_input_send_mode_request_tag 44
|
||||
#define alox_UartMessage_input_send_mode_response_tag 45
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define alox_UartMessage_FIELDLIST(X, a) \
|
||||
@@ -887,7 +942,9 @@ X(a, STATIC, ONEOF, MESSAGE, (payload,tap_config_request,payload.tap_confi
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,tap_config_response,payload.tap_config_response), 40) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,ble_stream_tick,payload.ble_stream_tick), 41) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,client_id_map_reset_request,payload.client_id_map_reset_request), 42) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,client_id_map_reset_response,payload.client_id_map_reset_response), 43)
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,client_id_map_reset_response,payload.client_id_map_reset_response), 43) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,input_send_mode_request,payload.input_send_mode_request), 44) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,input_send_mode_response,payload.input_send_mode_response), 45)
|
||||
#define alox_UartMessage_CALLBACK NULL
|
||||
#define alox_UartMessage_DEFAULT NULL
|
||||
#define alox_UartMessage_payload_ack_payload_MSGTYPE alox_Ack
|
||||
@@ -928,6 +985,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload,client_id_map_reset_response,payload
|
||||
#define alox_UartMessage_payload_ble_stream_tick_MSGTYPE alox_BleStreamTick
|
||||
#define alox_UartMessage_payload_client_id_map_reset_request_MSGTYPE alox_ClientIdMapResetRequest
|
||||
#define alox_UartMessage_payload_client_id_map_reset_response_MSGTYPE alox_ClientIdMapResetResponse
|
||||
#define alox_UartMessage_payload_input_send_mode_request_MSGTYPE alox_InputSendModeRequest
|
||||
#define alox_UartMessage_payload_input_send_mode_response_MSGTYPE alox_InputSendModeResponse
|
||||
|
||||
#define alox_Ack_FIELDLIST(X, a) \
|
||||
|
||||
@@ -1014,6 +1073,22 @@ X(a, STATIC, SINGULAR, UINT32, slaves_updated, 4)
|
||||
#define alox_AccelStreamResponse_CALLBACK NULL
|
||||
#define alox_AccelStreamResponse_DEFAULT NULL
|
||||
|
||||
#define alox_InputSendModeRequest_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, BOOL, write, 1) \
|
||||
X(a, STATIC, SINGULAR, UENUM, mode, 2) \
|
||||
X(a, STATIC, SINGULAR, UINT32, client_id, 3) \
|
||||
X(a, STATIC, SINGULAR, BOOL, all_clients, 4)
|
||||
#define alox_InputSendModeRequest_CALLBACK NULL
|
||||
#define alox_InputSendModeRequest_DEFAULT NULL
|
||||
|
||||
#define alox_InputSendModeResponse_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, BOOL, success, 1) \
|
||||
X(a, STATIC, SINGULAR, UENUM, mode, 2) \
|
||||
X(a, STATIC, SINGULAR, UINT32, client_id, 3) \
|
||||
X(a, STATIC, SINGULAR, UINT32, slaves_updated, 4)
|
||||
#define alox_InputSendModeResponse_CALLBACK NULL
|
||||
#define alox_InputSendModeResponse_DEFAULT NULL
|
||||
|
||||
#define alox_BatteryStatusRequest_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, client_id, 1) \
|
||||
X(a, STATIC, SINGULAR, BOOL, all_clients, 2)
|
||||
@@ -1312,6 +1387,8 @@ extern const pb_msgdesc_t alox_AccelDeadzoneRequest_msg;
|
||||
extern const pb_msgdesc_t alox_AccelDeadzoneResponse_msg;
|
||||
extern const pb_msgdesc_t alox_AccelStreamRequest_msg;
|
||||
extern const pb_msgdesc_t alox_AccelStreamResponse_msg;
|
||||
extern const pb_msgdesc_t alox_InputSendModeRequest_msg;
|
||||
extern const pb_msgdesc_t alox_InputSendModeResponse_msg;
|
||||
extern const pb_msgdesc_t alox_BatteryStatusRequest_msg;
|
||||
extern const pb_msgdesc_t alox_LipoReading_msg;
|
||||
extern const pb_msgdesc_t alox_BatterySample_msg;
|
||||
@@ -1363,6 +1440,8 @@ extern const pb_msgdesc_t alox_OtaSlaveProgressResponse_msg;
|
||||
#define alox_AccelDeadzoneResponse_fields &alox_AccelDeadzoneResponse_msg
|
||||
#define alox_AccelStreamRequest_fields &alox_AccelStreamRequest_msg
|
||||
#define alox_AccelStreamResponse_fields &alox_AccelStreamResponse_msg
|
||||
#define alox_InputSendModeRequest_fields &alox_InputSendModeRequest_msg
|
||||
#define alox_InputSendModeResponse_fields &alox_InputSendModeResponse_msg
|
||||
#define alox_BatteryStatusRequest_fields &alox_BatteryStatusRequest_msg
|
||||
#define alox_LipoReading_fields &alox_LipoReading_msg
|
||||
#define alox_BatterySample_fields &alox_BatterySample_msg
|
||||
@@ -1433,6 +1512,8 @@ extern const pb_msgdesc_t alox_OtaSlaveProgressResponse_msg;
|
||||
#define alox_EspNowFindMeResponse_size 8
|
||||
#define alox_EspNowUnicastTestRequest_size 12
|
||||
#define alox_EspNowUnicastTestResponse_size 8
|
||||
#define alox_InputSendModeRequest_size 12
|
||||
#define alox_InputSendModeResponse_size 16
|
||||
#define alox_LedRingProgressRequest_size 64
|
||||
#define alox_LedRingProgressResponse_size 32
|
||||
#define alox_LipoReading_size 8
|
||||
|
||||
@@ -42,6 +42,11 @@ enum MessageType {
|
||||
* online slaves), or on a slave clear local master/id binding only.
|
||||
*/
|
||||
CLIENT_ID_MAP_RESET = 34;
|
||||
/**
|
||||
* Host → master: get/set slave ESP-NOW send path for accel/tap
|
||||
* (best_effort / fast / wait / reliable).
|
||||
*/
|
||||
INPUT_SEND_MODE = 35;
|
||||
}
|
||||
|
||||
message UartMessage {
|
||||
@@ -85,6 +90,8 @@ message UartMessage {
|
||||
BleStreamTick ble_stream_tick = 41;
|
||||
ClientIdMapResetRequest client_id_map_reset_request = 42;
|
||||
ClientIdMapResetResponse client_id_map_reset_response = 43;
|
||||
InputSendModeRequest input_send_mode_request = 44;
|
||||
InputSendModeResponse input_send_mode_response = 45;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,6 +174,34 @@ message AccelStreamResponse {
|
||||
uint32 slaves_updated = 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Slave ESP-NOW TX path for ACCEL_SAMPLE / TAP_EVENT (debug A/B).
|
||||
* Maps 1:1 to esp_now_core_send_*.
|
||||
*/
|
||||
enum InputSendMode {
|
||||
INPUT_SEND_BEST_EFFORT = 0;
|
||||
INPUT_SEND_FAST = 1;
|
||||
INPUT_SEND_WAIT = 2;
|
||||
INPUT_SEND_RELIABLE = 3;
|
||||
}
|
||||
|
||||
// Host → master: get/set input send mode on slaves.
|
||||
// write=false: return last mode remembered on master (client_id ignored).
|
||||
// write=true: push mode via ESP-NOW (all_clients or one client_id).
|
||||
message InputSendModeRequest {
|
||||
bool write = 1;
|
||||
InputSendMode mode = 2;
|
||||
uint32 client_id = 3;
|
||||
bool all_clients = 4;
|
||||
}
|
||||
|
||||
message InputSendModeResponse {
|
||||
bool success = 1;
|
||||
InputSendMode mode = 2;
|
||||
uint32 client_id = 3;
|
||||
uint32 slaves_updated = 4;
|
||||
}
|
||||
|
||||
/** Host → master: read LiPo ADC voltages (master local and/or slaves via ESP-NOW). */
|
||||
message BatteryStatusRequest {
|
||||
/** 0 = master only; >0 = one slave; ignored when all_clients */
|
||||
|
||||
Reference in New Issue
Block a user