From ac223ada729a5a0cc22730bdd3e041f12a156ba3 Mon Sep 17 00:00:00 2001 From: simon Date: Sat, 6 Jun 2026 17:44:40 +0200 Subject: [PATCH] Added ECHO cmd and fixed some timing issues --- docs/ARCHITECTURE.md | 2 +- docs/DOCUMENTATION.md | 30 +++ goTool/README.md | 13 ++ goTool/api_serve.go | 44 ++++ goTool/client_api.go | 75 +++++++ goTool/cmd_echo_ping.go | 26 +++ goTool/docs/API_REST.md | 49 +++++ goTool/docs/API_WEBSOCKET.md | 60 ++--- goTool/main.go | 5 +- goTool/pb/uart_messages.pb.go | 352 ++++++++++++++++++++++-------- goTool/webui/index.html | 52 ++++- main/CMakeLists.txt | 2 + main/cmd/cmd_espnow_echo_ping.c | 70 ++++++ main/cmd/cmd_espnow_echo_ping.h | 6 + main/cmd/cmd_handler.c | 2 + main/esp_now_comm.h | 11 + main/esp_now_core.c | 136 ++++++++++-- main/esp_now_master.c | 117 +++++++++- main/esp_now_slave.c | 79 ++++++- main/led_ring.c | 2 +- main/powerpod.c | 5 + main/proto/esp_now_messages.pb.c | 6 + main/proto/esp_now_messages.pb.h | 71 +++++- main/proto/esp_now_messages.proto | 19 ++ main/proto/uart_messages.pb.c | 6 + main/proto/uart_messages.pb.h | 66 +++++- main/proto/uart_messages.proto | 20 ++ main/uart.c | 3 +- main/uart.h | 5 +- 29 files changed, 1182 insertions(+), 152 deletions(-) create mode 100644 goTool/cmd_echo_ping.go create mode 100644 main/cmd/cmd_espnow_echo_ping.c create mode 100644 main/cmd/cmd_espnow_echo_ping.h diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index e43d0fa..7cea06c 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -205,7 +205,7 @@ sequenceDiagram ``` **Beispiel-Implementierung:** `main/cmd/cmd_accel_deadzone.c` -**Weitere Bridge-Handler:** `cmd_accel_stream.c`, `cmd_tap_notify.c`, `cmd_led_ring.c`, `cmd_espnow_find_me.c`, `cmd_restart.c`, `cmd_espnow_unicast_test.c`, `cmd/cmd_ota.c` (OTA + `ota_espnow.c`). +**Weitere Bridge-Handler:** `cmd_accel_stream.c`, `cmd_tap_notify.c`, `cmd_led_ring.c`, `cmd_espnow_find_me.c`, `cmd_restart.c`, `cmd_espnow_unicast_test.c`, `cmd_espnow_echo_ping.c`, `cmd/cmd_ota.c` (OTA + `ota_espnow.c`). **Nur Master / nur Cache (kein Slave-Roundtrip):** `cmd_client_info.c`, `cmd_battery.c`, `cmd_cache_status.c`, `cmd_version.c`. diff --git a/docs/DOCUMENTATION.md b/docs/DOCUMENTATION.md index 471ca95..58719e9 100644 --- a/docs/DOCUMENTATION.md +++ b/docs/DOCUMENTATION.md @@ -181,6 +181,8 @@ UART_CMD_REQ(&uart_msg, alox_UartMessage_accel_deadzone_request_tag, accel_deadz | `ESPNOW_FIND_ME` | M→S | `find_me` | LED-Locate | | `ESPNOW_RESTART` | M→S | `restart` | Reboot Slave | | `ESPNOW_UNICAST_TEST` | M→S | `unicast_test` | Link-Test | +| `ESPNOW_ECHO_PING` | M→S | `echo_ping` | Latenztest (Host-Timestamp + `master_time_us`) | +| `ESPNOW_ECHO_PONG` | S→M | `echo_pong` | Echo unverändert zurück zum Master | | `ESPNOW_OTA_*` | M↔S | `ota_*` | Firmware-Verteilung | ### 6.3 Zeitkonstanten (`esp_now_comm.c`) @@ -193,6 +195,7 @@ UART_CMD_REQ(&uart_msg, alox_UartMessage_accel_deadzone_request_tag, accel_deadz | Master-Verlust (Slave) | 5 s ohne Discover | | Accel-Stream | 16 ms | | Batterie-Report | 30 s (+ einmal 150 ms nach Join) | +| Echo-Ping Timeout (Master) | 500 ms (`ESPNOW_ECHO_PING_TIMEOUT_MS`) | ### 6.4 `EspNowSlavePresence` @@ -229,6 +232,7 @@ Nur auf dem **Master** registriert (`powerpod.c`). IDs aus `MessageType` in `uar | 26 | BATTERY_STATUS | `cmd_battery.c` | Cache LiPo Master + Slaves | | 27 | TAP_NOTIFY | `cmd_tap_notify.c` | Tap-Weiterleitung konfigurieren | | 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) | ### 7.1 VERSION (3) @@ -287,6 +291,31 @@ Nur auf dem **Master** registriert (`powerpod.c`). IDs aus `MessageType` in `uar Minimaler Master→Slave-Ping; Slave loggt `UNICAST TEST OK`. +### 7.11 ESPNOW_ECHO_PING (30) + +Round-Trip-Latenztest zu einem **Slave** (`client_id` > 0, muss in der Registry sein). + +**Ablauf:** + +1. Host (goTool) setzt `timestamp_us` (Unix-µs) und sendet `EspNowEchoPingRequest` per UART. +2. Master (`cmd_espnow_echo_ping.c`) löst MAC aus Registry auf, ruft `esp_now_comm_echo_ping()` auf. +3. Master sendet `ESPNOW_ECHO_PING` mit `host_timestamp_us` und `master_time_us` (`esp_timer_get_time()` kurz vor Send). +4. Slave (`handle_echo_ping`) antwortet mit `ESPNOW_ECHO_PONG` (Felder unverändert). +5. Master empfängt Pong, berechnet `esp_rtt_us = esp_timer_get_time() - master_time_us`, antwortet per UART. + +**Request:** `client_id`, `timestamp_us` (vom Host gesetzt). + +**Response:** `success`, `client_id`, `timestamp_us` (echoed), `esp_rtt_us` (nur bei Erfolg). + +| Feld | Quelle | Bedeutung | +|------|--------|-----------| +| `timestamp_us` | Host → Slave → Host | Korrelations-ID; muss mit Request übereinstimmen | +| `esp_rtt_us` | Master | Rohe µs-Differenz von `esp_timer_get_time()` (Ping-Send → Pong-Empfang im `recv_cb`) | + +**Implementierung:** `main/cmd/cmd_espnow_echo_ping.c`, `esp_now_comm_echo_ping()` in `esp_now_master.c`, Slave `handle_echo_ping` in `esp_now_slave.c`. + +**Host-seitig (goTool):** `rtt_ms` = volle UART-Kette (Send bis Response-Empfang); unabhängig von `esp_rtt_us`. + --- ## 8. OTA @@ -427,6 +456,7 @@ Includes in generierten `.pb.c` müssen `"uart_messages.pb.h"` heißen (nicht `m | `cmd_espnow_find_me.c` | FIND_ME | | `cmd_restart.c` | RESTART | | `cmd_espnow_unicast_test.c` | ESPNOW_UNICAST_TEST | +| `cmd_espnow_echo_ping.c` | ESPNOW_ECHO_PING | | `cmd_ota.c` | OTA_* | | `cmd_ota_slave_progress.c` | OTA_SLAVE_PROGRESS | diff --git a/goTool/README.md b/goTool/README.md index c0aa137..e2172fb 100644 --- a/goTool/README.md +++ b/goTool/README.md @@ -28,6 +28,7 @@ go run . -port /dev/ttyUSB0 clients | `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 | | `unicast-test` | `0x07` | Sends ESP-NOW unicast test to one slave (`-client`, `-seq`) | +| `echo-ping` | `0x1e` | ESP-NOW echo round-trip to one slave (`-client`); prints `rtt_ms` (host UART chain) and `esp_rtt_us` (master ESP-NOW, raw µs) | | `test` | — | Run an automated scenario (JSON configs under `testdata/`) | | `serve` | — | Web dashboard at `http://localhost:8080` (WebSocket live updates) | | `ota` | 16–19 | UART firmware upload to master; firmware then pushes to slaves via ESP-NOW | @@ -113,8 +114,20 @@ go run . -port /dev/ttyUSB0 unicast-test -client 16 -seq 42 On success the slave serial log should show `UNICAST TEST OK from master … seq=42`. +```bash +go run . -port /dev/ttyUSB0 echo-ping -client 16 +``` + +Measures latency to one slave. `rtt_ms` is the full host round-trip (UART + ESP-NOW + UART back). `esp_rtt_us` is the master-side ESP-NOW leg only (`esp_timer_get_time()` delta, raw microseconds from firmware). + Example output: +``` +echo ping: success=true client_id=16 rtt_ms=49.729 esp_rtt_us=18234 +``` + +`clients` example: + ``` clients (2): [0] id=42 mac=aabbccddeeff ver=1 available=true used=false last_ping=250 last_success_ping=250 diff --git a/goTool/api_serve.go b/goTool/api_serve.go index 0ba7d18..1d0e533 100644 --- a/goTool/api_serve.go +++ b/goTool/api_serve.go @@ -41,6 +41,19 @@ type unicastAPIResponse struct { Error string `json:"error,omitempty"` } +type echoPingAPIRequest struct { + ClientID uint32 `json:"client_id"` +} + +type echoPingAPIResponse struct { + Success bool `json:"success"` + ClientID uint32 `json:"client_id,omitempty"` + TimestampUs uint64 `json:"timestamp_us,omitempty"` + RttMs float64 `json:"rtt_ms"` + EspRttUs uint32 `json:"esp_rtt_us"` + Error string `json:"error,omitempty"` +} + type findMeAPIRequest struct { ClientID uint32 `json:"client_id"` } @@ -91,6 +104,13 @@ func mountServeAPI(mux *http.ServeMux, link *managedSerial, hub *wsHub, streamCt } serveUnicastTest(w, r, link) }) + mux.HandleFunc("/api/echo-ping", func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "method not allowed", http.StatusMethodNotAllowed) + return + } + serveEchoPing(w, r, link) + }) mux.HandleFunc("/api/find-me", func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "method not allowed", http.StatusMethodNotAllowed) @@ -316,6 +336,30 @@ func serveUnicastTest(w http.ResponseWriter, r *http.Request, link *managedSeria }) } +func serveEchoPing(w http.ResponseWriter, r *http.Request, link *managedSerial) { + var body echoPingAPIRequest + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + writeJSON(w, http.StatusBadRequest, echoPingAPIResponse{Error: "invalid JSON"}) + return + } + if body.ClientID == 0 { + writeJSON(w, http.StatusBadRequest, echoPingAPIResponse{Error: "client_id required"}) + return + } + result, err := link.EchoPing(body.ClientID) + if err != nil { + writeJSON(w, http.StatusServiceUnavailable, echoPingAPIResponse{Error: err.Error()}) + return + } + writeJSON(w, http.StatusOK, echoPingAPIResponse{ + Success: result.Success, + ClientID: result.ClientID, + TimestampUs: result.TimestampUs, + RttMs: result.RttMs, + EspRttUs: result.EspRttUs, + }) +} + func parseUintQuery(r *http.Request, key string, def uint32) (uint32, error) { s := r.URL.Query().Get(key) if s == "" { diff --git a/goTool/client_api.go b/goTool/client_api.go index 1ec0cb1..63f3884 100644 --- a/goTool/client_api.go +++ b/goTool/client_api.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "time" "google.golang.org/protobuf/proto" @@ -410,6 +411,66 @@ func (s *serialPort) espnowUnicastTest(clientID, seq uint32) (*pb.EspNowUnicastT return r, nil } +// EchoPingResult is the host-side round-trip for ESP-NOW echo ping. +type EchoPingResult struct { + Success bool `json:"success"` + ClientID uint32 `json:"client_id"` + TimestampUs uint64 `json:"timestamp_us"` + RttMs float64 `json:"rtt_ms"` // goTool: full UART round-trip + EspRttUs uint32 `json:"esp_rtt_us"` // master: µs delta ping send → pong recv +} + +func (s *serialPort) echoPing(clientID uint32) (*EchoPingResult, error) { + t0 := time.Now() + timestampUs := uint64(t0.UnixMicro()) + req := &pb.EspNowEchoPingRequest{ + ClientId: clientID, + TimestampUs: timestampUs, + } + msg := &pb.UartMessage{ + Type: pb.MessageType_ESPNOW_ECHO_PING, + Payload: &pb.UartMessage_EspnowEchoPingRequest{ + EspnowEchoPingRequest: req, + }, + } + body, err := proto.Marshal(msg) + if err != nil { + return nil, fmt.Errorf("encode: %w", err) + } + payload := append([]byte{byte(pb.MessageType_ESPNOW_ECHO_PING)}, body...) + respPayload, err := s.exchangePayload(payload, "ESPNOW_ECHO_PING") + if err != nil { + return nil, err + } + rttMs := float64(time.Since(t0).Microseconds()) / 1000.0 + + var respMsg pb.UartMessage + if err := proto.Unmarshal(respPayload[1:], &respMsg); err != nil { + return nil, fmt.Errorf("decode: %w", err) + } + r := respMsg.GetEspnowEchoPingResponse() + if r == nil { + return nil, fmt.Errorf("missing espnow_echo_ping_response") + } + if !r.GetSuccess() { + return &EchoPingResult{ + Success: false, + ClientID: r.GetClientId(), + RttMs: rttMs, + }, nil + } + if r.GetTimestampUs() != timestampUs { + return nil, fmt.Errorf("timestamp mismatch: sent %d got %d", timestampUs, r.GetTimestampUs()) + } + return &EchoPingResult{ + Success: true, + ClientID: r.GetClientId(), + TimestampUs: r.GetTimestampUs(), + RttMs: rttMs, + EspRttUs: r.GetEspRttUs(), + }, nil +} + func (m *managedSerial) FindMe(clientID uint32) error { return m.withPort(func(sp *serialPort) error { return runFindMeClient(sp, clientID) @@ -490,6 +551,20 @@ func (s *serialPort) EspnowUnicastTest(clientID, seq uint32) (*pb.EspNowUnicastT return s.espnowUnicastTest(clientID, seq) } +func (s *serialPort) EchoPing(clientID uint32) (*EchoPingResult, error) { + return s.echoPing(clientID) +} + +func (m *managedSerial) EchoPing(clientID uint32) (*EchoPingResult, error) { + var result *EchoPingResult + err := m.withPort(func(sp *serialPort) error { + var e error + result, e = sp.echoPing(clientID) + return e + }) + return result, err +} + func (s *serialPort) LedRing(req *pb.LedRingProgressRequest) (*pb.LedRingProgressResponse, error) { return s.ledRingProgress(req) } diff --git a/goTool/cmd_echo_ping.go b/goTool/cmd_echo_ping.go new file mode 100644 index 0000000..38c61b5 --- /dev/null +++ b/goTool/cmd_echo_ping.go @@ -0,0 +1,26 @@ +package main + +import ( + "flag" + "fmt" +) + +func runEchoPing(sp *serialPort, args []string) error { + fs := flag.NewFlagSet("echo-ping", flag.ExitOnError) + clientID := fs.Uint("client", 0, "slave client id from `clients`") + if err := fs.Parse(args); err != nil { + return err + } + if *clientID == 0 { + return fmt.Errorf("client id required (see `gotool clients`)") + } + + r, err := sp.echoPing(uint32(*clientID)) + if err != nil { + return err + } + + fmt.Printf("echo ping: success=%v client_id=%d rtt_ms=%.3f esp_rtt_us=%d\n", + r.Success, r.ClientID, r.RttMs, r.EspRttUs) + return nil +} diff --git a/goTool/docs/API_REST.md b/goTool/docs/API_REST.md index 9628146..87bc3c7 100644 --- a/goTool/docs/API_REST.md +++ b/goTool/docs/API_REST.md @@ -216,6 +216,54 @@ Content-Type: application/json {"client_id": 16, "seq": 42} ``` +### Echo ping (ESP-NOW round-trip latency) + +```http +POST /api/echo-ping +Content-Type: application/json +{"client_id": 16} +``` + +`client_id` must be a registered slave id (`> 0`). The host sends a microsecond timestamp; the master forwards it over ESP-NOW and the slave echoes it back unchanged. + +**Flow:** Host → UART → `cmd_espnow_echo_ping` → `ESPNOW_ECHO_PING` (with `master_time_us` from `esp_timer_get_time()`) → Slave → `ESPNOW_ECHO_PONG` → Master `recv_cb` → UART response. + +**Response fields:** + +| Field | Unit | Meaning | +|-------|------|---------| +| `success` | — | `true` if pong received within 500 ms | +| `client_id` | — | Echo of request | +| `timestamp_us` | µs (Unix) | Echoed host timestamp; must match request on success | +| `rtt_ms` | ms | **Host-side** round-trip: goTool send → UART response (full chain incl. USB serial) | +| `esp_rtt_us` | µs | **Master-side** ESP-NOW only: `esp_timer_get_time()` delta from ping send to pong recv | + +`esp_rtt_us` is the raw firmware value (microseconds, not converted). The web dashboard displays it converted to milliseconds for readability (`esp_rtt_us / 1000`, 3 decimal places). The success banner stays visible for at least 5 seconds. + +```json +{ + "success": true, + "client_id": 16, + "timestamp_us": 1717654321123456, + "rtt_ms": 49.729, + "esp_rtt_us": 18234 +} +``` + +On failure (`success: false`), `esp_rtt_us` is omitted; `rtt_ms` still reflects the host round-trip. HTTP 503 if UART exchange fails (e.g. timeout, client not in registry). + +**CLI:** + +```bash +go run . -port /dev/ttyUSB0 echo-ping -client 16 +``` + +Example output: + +``` +echo ping: success=true client_id=16 rtt_ms=49.729 esp_rtt_us=18234 +``` + ### Find me ```http @@ -280,5 +328,6 @@ Same as external API: | Einzelner Slave | `client_id: ` | | Alle Slaves deadzone | `all_clients` + `slaves_only` on POST | | Unicast test | `POST /api/unicast-test` | +| Echo ping | `POST /api/echo-ping` (per-slave latency; UI shows Host ms + ESP ms) | | Tap notify S/D/T | `PUT /api/clients/{id}/tap-notify` | | Tap receive (UI) | Live stream + tap notify; see WebSocket doc for external API | diff --git a/goTool/docs/API_WEBSOCKET.md b/goTool/docs/API_WEBSOCKET.md index f5b4f1e..916d338 100644 --- a/goTool/docs/API_WEBSOCKET.md +++ b/goTool/docs/API_WEBSOCKET.md @@ -5,6 +5,7 @@ External API: `ws://localhost:8081/ws` (default `-api-addr`, disable with empty Start with `go run . -port /dev/ttyUSB0 serve`. --- + ## Connection flow 1. Connect → server sends `hello` (push off; defaults and command list). @@ -19,19 +20,23 @@ On disconnect, `set_stream` state for that socket is dropped. Firmware settings ## Two layers (firmware vs host) -| Layer | Commands | Effect | -|-------|----------|--------| + +| Layer | Commands | Effect | +| ------------------ | ------------------------------------ | ------------------------------------------------------------------ | | Firmware (ESP-NOW) | `set_input_stream`, `set_tap_notify` | Per `client_id`: slave sends accel and/or tap events to the master | -| This connection | `set_stream` | Whether you receive push JSON on this socket | +| This connection | `set_stream` | Whether you receive push JSON on this socket | + UART polling runs only when at least one connection has `receive_input: true` **and** at least one slave streams input or has tap notify enabled. `set_tap_notify` alone does not enable push — you still need `set_stream`. ### Push timing (per connection) -| Field | Where | Meaning | -|-------|-------|---------| + +| Field | Where | Meaning | +| ------------- | -------------------------------------- | ------------------------------------------------------------ | | `interval_ms` | `hello`, `set_stream`, `stream_status` | Minimum ms between `input` pushes on this socket (1 … 10000) | -| `pre_fetch` | `set_stream`, `stream_status` | Ms before each push when the host starts the UART cache read | +| `pre_fetch` | `set_stream`, `stream_status` | Ms before each push when the host starts the UART cache read | + Global UART poll interval = minimum `interval_ms` among all connections with push enabled. @@ -74,17 +79,19 @@ Combines latest accel cache and visible tap state for every slave slot on the ma } ``` -| Field | Meaning | -|-------|---------| -| `t` | Unix timestamp in nanoseconds when the host read the cache | -| `success` | `true` if `CACHE_STATUS` succeeded | -| `clients[]` | One entry per slave slot (includes invalid/stale entries) | -| `client_id` | Same id as in `list_clients` | -| `valid` | `false` if no accel sample yet or stale; omit `x`/`y`/`z` when false | -| `x`, `y`, `z` | Raw accelerometer LSB (BMA456, ±2 g) | -| `accel_age_ms` | Ms since the master received this accel sample | -| `tap_kind` | `"single"`, `"double"`, or `"triple"`; omit when no recent tap | -| `tap_age_ms` | Ms since tap in master cache; omit with `tap_kind` | + +| Field | Meaning | +| -------------- | -------------------------------------------------------------------- | +| `t` | Unix timestamp in nanoseconds when the host read the cache | +| `success` | `true` if `CACHE_STATUS` succeeded | +| `clients[]` | One entry per slave slot (includes invalid/stale entries) | +| `client_id` | Same id as in `list_clients` | +| `valid` | `false` if no accel sample yet or stale; omit `x`/`y`/`z` when false | +| `x`, `y`, `z` | Raw accelerometer LSB (BMA456, ±2 g) | +| `accel_age_ms` | Ms since the master received this accel sample | +| `tap_kind` | `"single"`, `"double"`, or `"triple"`; omit when no recent tap | +| `tap_age_ms` | Ms since tap in master cache; omit with `tap_kind` | + Tap events stay visible for `tap_display_min_ms` (2000, in `hello`) after the API first saw them. @@ -198,14 +205,16 @@ Response `tap_notify_status`: {"type":"set_led_ring","mode":"find-me","all_clients":true,"slaves_only":true} ``` -| Request `mode` | Notes | -|----------------|--------| -| `clear` | Turn off | -| `color` | Full ring RGB + `intensity` | -| `progress` | `progress` 0–100 | -| `digit` | `digit` 0–10 | -| `blink` | `blink_ms`, `blink_count` | -| `find-me` | Locate pod | + +| Request `mode` | Notes | +| -------------- | --------------------------- | +| `clear` | Turn off | +| `color` | Full ring RGB + `intensity` | +| `progress` | `progress` 0–100 | +| `digit` | `digit` 0–10 | +| `blink` | `blink_ms`, `blink_count` | +| `find-me` | Locate pod | + Target: `client_id` (`0` = master) or `all_clients` (+ optional `slaves_only`). @@ -240,3 +249,4 @@ Response `battery_status`: ] } ``` + diff --git a/goTool/main.go b/goTool/main.go index 46c1671..47f7188 100644 --- a/goTool/main.go +++ b/goTool/main.go @@ -19,6 +19,7 @@ func usage() { 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, " unicast-test send ESP-NOW unicast test to one slave\n") + fmt.Fprintf(os.Stderr, " echo-ping ESP-NOW timestamp echo round-trip to one slave\n") fmt.Fprintf(os.Stderr, " test run automated scenario (see testdata/)\n") fmt.Fprintf(os.Stderr, " serve web dashboard (Bootstrap + WebSocket)\n") fmt.Fprintf(os.Stderr, " ota UART OTA upload (A/B partitions)\n") @@ -52,7 +53,7 @@ func main() { os.Exit(2) } 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", "led-ring", "led_ring", "find-me", "find_me", "restart", "ota", "ota-progress", "ota_progress": + 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", "ota", "ota-progress", "ota_progress": if *portName == "" { fmt.Fprintf(os.Stderr, "command %q requires -port\n\n", cmd) usage() @@ -78,6 +79,8 @@ func main() { runErr = runCacheStatus(sp) case "unicast-test", "unicast_test": runErr = runUnicastTest(sp, flag.Args()[1:]) + case "echo-ping", "echo_ping": + runErr = runEchoPing(sp, flag.Args()[1:]) case "led-ring", "led_ring": runErr = runLedRing(sp, flag.Args()[1:]) case "find-me", "find_me": diff --git a/goTool/pb/uart_messages.pb.go b/goTool/pb/uart_messages.pb.go index 923c75f..9735604 100644 --- a/goTool/pb/uart_messages.pb.go +++ b/goTool/pb/uart_messages.pb.go @@ -46,6 +46,8 @@ const ( MessageType_TAP_NOTIFY MessageType = 27 // * Combined cached accel + tap poll (one UART round-trip, ~16 ms cadence). MessageType_CACHE_STATUS MessageType = 29 + // * Host → master → slave → master: timestamp echo round-trip (latency test). + MessageType_ESPNOW_ECHO_PING MessageType = 30 ) // Enum value maps for MessageType. @@ -72,6 +74,7 @@ var ( 26: "BATTERY_STATUS", 27: "TAP_NOTIFY", 29: "CACHE_STATUS", + 30: "ESPNOW_ECHO_PING", } MessageType_value = map[string]int32{ "UNKNOWN": 0, @@ -95,6 +98,7 @@ var ( "BATTERY_STATUS": 26, "TAP_NOTIFY": 27, "CACHE_STATUS": 29, + "ESPNOW_ECHO_PING": 30, } ) @@ -211,6 +215,8 @@ type UartMessage struct { // *UartMessage_TapNotifyResponse // *UartMessage_CacheStatusRequest // *UartMessage_CacheStatusResponse + // *UartMessage_EspnowEchoPingRequest + // *UartMessage_EspnowEchoPingResponse Payload isUartMessage_Payload `protobuf_oneof:"payload"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -521,6 +527,24 @@ func (x *UartMessage) GetCacheStatusResponse() *CacheStatusResponse { return nil } +func (x *UartMessage) GetEspnowEchoPingRequest() *EspNowEchoPingRequest { + if x != nil { + if x, ok := x.Payload.(*UartMessage_EspnowEchoPingRequest); ok { + return x.EspnowEchoPingRequest + } + } + return nil +} + +func (x *UartMessage) GetEspnowEchoPingResponse() *EspNowEchoPingResponse { + if x != nil { + if x, ok := x.Payload.(*UartMessage_EspnowEchoPingResponse); ok { + return x.EspnowEchoPingResponse + } + } + return nil +} + type isUartMessage_Payload interface { isUartMessage_Payload() } @@ -641,6 +665,14 @@ type UartMessage_CacheStatusResponse struct { CacheStatusResponse *CacheStatusResponse `protobuf:"bytes,34,opt,name=cache_status_response,json=cacheStatusResponse,proto3,oneof"` } +type UartMessage_EspnowEchoPingRequest struct { + EspnowEchoPingRequest *EspNowEchoPingRequest `protobuf:"bytes,35,opt,name=espnow_echo_ping_request,json=espnowEchoPingRequest,proto3,oneof"` +} + +type UartMessage_EspnowEchoPingResponse struct { + EspnowEchoPingResponse *EspNowEchoPingResponse `protobuf:"bytes,36,opt,name=espnow_echo_ping_response,json=espnowEchoPingResponse,proto3,oneof"` +} + func (*UartMessage_AckPayload) isUartMessage_Payload() {} func (*UartMessage_EchoPayload) isUartMessage_Payload() {} @@ -699,6 +731,10 @@ func (*UartMessage_CacheStatusRequest) isUartMessage_Payload() {} func (*UartMessage_CacheStatusResponse) isUartMessage_Payload() {} +func (*UartMessage_EspnowEchoPingRequest) isUartMessage_Payload() {} + +func (*UartMessage_EspnowEchoPingResponse) isUartMessage_Payload() {} + type Ack struct { state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields @@ -2329,6 +2365,130 @@ func (x *EspNowUnicastTestResponse) GetSeq() uint32 { return 0 } +// * Host → master: ESP-NOW echo ping to one slave (timestamp echoed back). +type EspNowEchoPingRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + ClientId uint32 `protobuf:"varint,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` + // * Microseconds since Unix epoch (host clock). + TimestampUs uint64 `protobuf:"varint,2,opt,name=timestamp_us,json=timestampUs,proto3" json:"timestamp_us,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *EspNowEchoPingRequest) Reset() { + *x = EspNowEchoPingRequest{} + mi := &file_uart_messages_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *EspNowEchoPingRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EspNowEchoPingRequest) ProtoMessage() {} + +func (x *EspNowEchoPingRequest) ProtoReflect() protoreflect.Message { + mi := &file_uart_messages_proto_msgTypes[27] + 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 EspNowEchoPingRequest.ProtoReflect.Descriptor instead. +func (*EspNowEchoPingRequest) Descriptor() ([]byte, []int) { + return file_uart_messages_proto_rawDescGZIP(), []int{27} +} + +func (x *EspNowEchoPingRequest) GetClientId() uint32 { + if x != nil { + return x.ClientId + } + return 0 +} + +func (x *EspNowEchoPingRequest) GetTimestampUs() uint64 { + if x != nil { + return x.TimestampUs + } + return 0 +} + +type EspNowEchoPingResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"` + ClientId uint32 `protobuf:"varint,2,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` + // * Echoed host timestamp from goTool request. + TimestampUs uint64 `protobuf:"varint,3,opt,name=timestamp_us,json=timestampUs,proto3" json:"timestamp_us,omitempty"` + // * esp_timer_get_time() delta from ping send to pong recv (master→slave→master). + EspRttUs uint32 `protobuf:"varint,4,opt,name=esp_rtt_us,json=espRttUs,proto3" json:"esp_rtt_us,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *EspNowEchoPingResponse) Reset() { + *x = EspNowEchoPingResponse{} + mi := &file_uart_messages_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *EspNowEchoPingResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EspNowEchoPingResponse) ProtoMessage() {} + +func (x *EspNowEchoPingResponse) ProtoReflect() protoreflect.Message { + mi := &file_uart_messages_proto_msgTypes[28] + 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 EspNowEchoPingResponse.ProtoReflect.Descriptor instead. +func (*EspNowEchoPingResponse) Descriptor() ([]byte, []int) { + return file_uart_messages_proto_rawDescGZIP(), []int{28} +} + +func (x *EspNowEchoPingResponse) GetSuccess() bool { + if x != nil { + return x.Success + } + return false +} + +func (x *EspNowEchoPingResponse) GetClientId() uint32 { + if x != nil { + return x.ClientId + } + return 0 +} + +func (x *EspNowEchoPingResponse) GetTimestampUs() uint64 { + if x != nil { + return x.TimestampUs + } + return 0 +} + +func (x *EspNowEchoPingResponse) GetEspRttUs() uint32 { + if x != nil { + return x.EspRttUs + } + return 0 +} + // Host → master: LED ring on master (client_id=0) and/or slaves via ESP-NOW. // mode: 0=clear, 1=progress (0–100 %), 2=digit (0–10), 3=blink, 4=find-me, 5=all LEDs solid color. type LedRingProgressRequest struct { @@ -2359,7 +2519,7 @@ type LedRingProgressRequest struct { func (x *LedRingProgressRequest) Reset() { *x = LedRingProgressRequest{} - mi := &file_uart_messages_proto_msgTypes[27] + mi := &file_uart_messages_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2371,7 +2531,7 @@ func (x *LedRingProgressRequest) String() string { func (*LedRingProgressRequest) ProtoMessage() {} func (x *LedRingProgressRequest) ProtoReflect() protoreflect.Message { - mi := &file_uart_messages_proto_msgTypes[27] + mi := &file_uart_messages_proto_msgTypes[29] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2384,7 +2544,7 @@ func (x *LedRingProgressRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use LedRingProgressRequest.ProtoReflect.Descriptor instead. func (*LedRingProgressRequest) Descriptor() ([]byte, []int) { - return file_uart_messages_proto_rawDescGZIP(), []int{27} + return file_uart_messages_proto_rawDescGZIP(), []int{29} } func (x *LedRingProgressRequest) GetMode() uint32 { @@ -2485,7 +2645,7 @@ type LedRingProgressResponse struct { func (x *LedRingProgressResponse) Reset() { *x = LedRingProgressResponse{} - mi := &file_uart_messages_proto_msgTypes[28] + mi := &file_uart_messages_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2497,7 +2657,7 @@ func (x *LedRingProgressResponse) String() string { func (*LedRingProgressResponse) ProtoMessage() {} func (x *LedRingProgressResponse) ProtoReflect() protoreflect.Message { - mi := &file_uart_messages_proto_msgTypes[28] + mi := &file_uart_messages_proto_msgTypes[30] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2510,7 +2670,7 @@ func (x *LedRingProgressResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use LedRingProgressResponse.ProtoReflect.Descriptor instead. func (*LedRingProgressResponse) Descriptor() ([]byte, []int) { - return file_uart_messages_proto_rawDescGZIP(), []int{28} + return file_uart_messages_proto_rawDescGZIP(), []int{30} } func (x *LedRingProgressResponse) GetSuccess() bool { @@ -2565,7 +2725,7 @@ type EspNowFindMeRequest struct { func (x *EspNowFindMeRequest) Reset() { *x = EspNowFindMeRequest{} - mi := &file_uart_messages_proto_msgTypes[29] + mi := &file_uart_messages_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2577,7 +2737,7 @@ func (x *EspNowFindMeRequest) String() string { func (*EspNowFindMeRequest) ProtoMessage() {} func (x *EspNowFindMeRequest) ProtoReflect() protoreflect.Message { - mi := &file_uart_messages_proto_msgTypes[29] + mi := &file_uart_messages_proto_msgTypes[31] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2590,7 +2750,7 @@ func (x *EspNowFindMeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use EspNowFindMeRequest.ProtoReflect.Descriptor instead. func (*EspNowFindMeRequest) Descriptor() ([]byte, []int) { - return file_uart_messages_proto_rawDescGZIP(), []int{29} + return file_uart_messages_proto_rawDescGZIP(), []int{31} } func (x *EspNowFindMeRequest) GetClientId() uint32 { @@ -2610,7 +2770,7 @@ type EspNowFindMeResponse struct { func (x *EspNowFindMeResponse) Reset() { *x = EspNowFindMeResponse{} - mi := &file_uart_messages_proto_msgTypes[30] + mi := &file_uart_messages_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2622,7 +2782,7 @@ func (x *EspNowFindMeResponse) String() string { func (*EspNowFindMeResponse) ProtoMessage() {} func (x *EspNowFindMeResponse) ProtoReflect() protoreflect.Message { - mi := &file_uart_messages_proto_msgTypes[30] + mi := &file_uart_messages_proto_msgTypes[32] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2635,7 +2795,7 @@ func (x *EspNowFindMeResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use EspNowFindMeResponse.ProtoReflect.Descriptor instead. func (*EspNowFindMeResponse) Descriptor() ([]byte, []int) { - return file_uart_messages_proto_rawDescGZIP(), []int{30} + return file_uart_messages_proto_rawDescGZIP(), []int{32} } func (x *EspNowFindMeResponse) GetSuccess() bool { @@ -2662,7 +2822,7 @@ type RestartRequest struct { func (x *RestartRequest) Reset() { *x = RestartRequest{} - mi := &file_uart_messages_proto_msgTypes[31] + mi := &file_uart_messages_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2674,7 +2834,7 @@ func (x *RestartRequest) String() string { func (*RestartRequest) ProtoMessage() {} func (x *RestartRequest) ProtoReflect() protoreflect.Message { - mi := &file_uart_messages_proto_msgTypes[31] + mi := &file_uart_messages_proto_msgTypes[33] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2687,7 +2847,7 @@ func (x *RestartRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RestartRequest.ProtoReflect.Descriptor instead. func (*RestartRequest) Descriptor() ([]byte, []int) { - return file_uart_messages_proto_rawDescGZIP(), []int{31} + return file_uart_messages_proto_rawDescGZIP(), []int{33} } func (x *RestartRequest) GetClientId() uint32 { @@ -2707,7 +2867,7 @@ type RestartResponse struct { func (x *RestartResponse) Reset() { *x = RestartResponse{} - mi := &file_uart_messages_proto_msgTypes[32] + mi := &file_uart_messages_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2719,7 +2879,7 @@ func (x *RestartResponse) String() string { func (*RestartResponse) ProtoMessage() {} func (x *RestartResponse) ProtoReflect() protoreflect.Message { - mi := &file_uart_messages_proto_msgTypes[32] + mi := &file_uart_messages_proto_msgTypes[34] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2732,7 +2892,7 @@ func (x *RestartResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RestartResponse.ProtoReflect.Descriptor instead. func (*RestartResponse) Descriptor() ([]byte, []int) { - return file_uart_messages_proto_rawDescGZIP(), []int{32} + return file_uart_messages_proto_rawDescGZIP(), []int{34} } func (x *RestartResponse) GetSuccess() bool { @@ -2759,7 +2919,7 @@ type OtaStartPayload struct { func (x *OtaStartPayload) Reset() { *x = OtaStartPayload{} - mi := &file_uart_messages_proto_msgTypes[33] + mi := &file_uart_messages_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2771,7 +2931,7 @@ func (x *OtaStartPayload) String() string { func (*OtaStartPayload) ProtoMessage() {} func (x *OtaStartPayload) ProtoReflect() protoreflect.Message { - mi := &file_uart_messages_proto_msgTypes[33] + mi := &file_uart_messages_proto_msgTypes[35] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2784,7 +2944,7 @@ func (x *OtaStartPayload) ProtoReflect() protoreflect.Message { // Deprecated: Use OtaStartPayload.ProtoReflect.Descriptor instead. func (*OtaStartPayload) Descriptor() ([]byte, []int) { - return file_uart_messages_proto_rawDescGZIP(), []int{33} + return file_uart_messages_proto_rawDescGZIP(), []int{35} } func (x *OtaStartPayload) GetTotalSize() uint32 { @@ -2805,7 +2965,7 @@ type OtaPayload struct { func (x *OtaPayload) Reset() { *x = OtaPayload{} - mi := &file_uart_messages_proto_msgTypes[34] + mi := &file_uart_messages_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2817,7 +2977,7 @@ func (x *OtaPayload) String() string { func (*OtaPayload) ProtoMessage() {} func (x *OtaPayload) ProtoReflect() protoreflect.Message { - mi := &file_uart_messages_proto_msgTypes[34] + mi := &file_uart_messages_proto_msgTypes[36] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2830,7 +2990,7 @@ func (x *OtaPayload) ProtoReflect() protoreflect.Message { // Deprecated: Use OtaPayload.ProtoReflect.Descriptor instead. func (*OtaPayload) Descriptor() ([]byte, []int) { - return file_uart_messages_proto_rawDescGZIP(), []int{34} + return file_uart_messages_proto_rawDescGZIP(), []int{36} } func (x *OtaPayload) GetSeq() uint32 { @@ -2856,7 +3016,7 @@ type OtaEndPayload struct { func (x *OtaEndPayload) Reset() { *x = OtaEndPayload{} - mi := &file_uart_messages_proto_msgTypes[35] + mi := &file_uart_messages_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2868,7 +3028,7 @@ func (x *OtaEndPayload) String() string { func (*OtaEndPayload) ProtoMessage() {} func (x *OtaEndPayload) ProtoReflect() protoreflect.Message { - mi := &file_uart_messages_proto_msgTypes[35] + mi := &file_uart_messages_proto_msgTypes[37] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2881,7 +3041,7 @@ func (x *OtaEndPayload) ProtoReflect() protoreflect.Message { // Deprecated: Use OtaEndPayload.ProtoReflect.Descriptor instead. func (*OtaEndPayload) Descriptor() ([]byte, []int) { - return file_uart_messages_proto_rawDescGZIP(), []int{35} + return file_uart_messages_proto_rawDescGZIP(), []int{37} } // Device → host status (also used as ACK after each 4 KiB written). @@ -2898,7 +3058,7 @@ type OtaStatusPayload struct { func (x *OtaStatusPayload) Reset() { *x = OtaStatusPayload{} - mi := &file_uart_messages_proto_msgTypes[36] + mi := &file_uart_messages_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2910,7 +3070,7 @@ func (x *OtaStatusPayload) String() string { func (*OtaStatusPayload) ProtoMessage() {} func (x *OtaStatusPayload) ProtoReflect() protoreflect.Message { - mi := &file_uart_messages_proto_msgTypes[36] + mi := &file_uart_messages_proto_msgTypes[38] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2923,7 +3083,7 @@ func (x *OtaStatusPayload) ProtoReflect() protoreflect.Message { // Deprecated: Use OtaStatusPayload.ProtoReflect.Descriptor instead. func (*OtaStatusPayload) Descriptor() ([]byte, []int) { - return file_uart_messages_proto_rawDescGZIP(), []int{36} + return file_uart_messages_proto_rawDescGZIP(), []int{38} } func (x *OtaStatusPayload) GetStatus() uint32 { @@ -2964,7 +3124,7 @@ type OtaSlaveProgressRequest struct { func (x *OtaSlaveProgressRequest) Reset() { *x = OtaSlaveProgressRequest{} - mi := &file_uart_messages_proto_msgTypes[37] + mi := &file_uart_messages_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2976,7 +3136,7 @@ func (x *OtaSlaveProgressRequest) String() string { func (*OtaSlaveProgressRequest) ProtoMessage() {} func (x *OtaSlaveProgressRequest) ProtoReflect() protoreflect.Message { - mi := &file_uart_messages_proto_msgTypes[37] + mi := &file_uart_messages_proto_msgTypes[39] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2989,7 +3149,7 @@ func (x *OtaSlaveProgressRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use OtaSlaveProgressRequest.ProtoReflect.Descriptor instead. func (*OtaSlaveProgressRequest) Descriptor() ([]byte, []int) { - return file_uart_messages_proto_rawDescGZIP(), []int{37} + return file_uart_messages_proto_rawDescGZIP(), []int{39} } func (x *OtaSlaveProgressRequest) GetClientId() uint32 { @@ -3013,7 +3173,7 @@ type OtaSlaveProgressEntry struct { func (x *OtaSlaveProgressEntry) Reset() { *x = OtaSlaveProgressEntry{} - mi := &file_uart_messages_proto_msgTypes[38] + mi := &file_uart_messages_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3025,7 +3185,7 @@ func (x *OtaSlaveProgressEntry) String() string { func (*OtaSlaveProgressEntry) ProtoMessage() {} func (x *OtaSlaveProgressEntry) ProtoReflect() protoreflect.Message { - mi := &file_uart_messages_proto_msgTypes[38] + mi := &file_uart_messages_proto_msgTypes[40] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3038,7 +3198,7 @@ func (x *OtaSlaveProgressEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use OtaSlaveProgressEntry.ProtoReflect.Descriptor instead. func (*OtaSlaveProgressEntry) Descriptor() ([]byte, []int) { - return file_uart_messages_proto_rawDescGZIP(), []int{38} + return file_uart_messages_proto_rawDescGZIP(), []int{40} } func (x *OtaSlaveProgressEntry) GetClientId() uint32 { @@ -3089,7 +3249,7 @@ type OtaSlaveProgressResponse struct { func (x *OtaSlaveProgressResponse) Reset() { *x = OtaSlaveProgressResponse{} - mi := &file_uart_messages_proto_msgTypes[39] + mi := &file_uart_messages_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3101,7 +3261,7 @@ func (x *OtaSlaveProgressResponse) String() string { func (*OtaSlaveProgressResponse) ProtoMessage() {} func (x *OtaSlaveProgressResponse) ProtoReflect() protoreflect.Message { - mi := &file_uart_messages_proto_msgTypes[39] + mi := &file_uart_messages_proto_msgTypes[41] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3114,7 +3274,7 @@ func (x *OtaSlaveProgressResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use OtaSlaveProgressResponse.ProtoReflect.Descriptor instead. func (*OtaSlaveProgressResponse) Descriptor() ([]byte, []int) { - return file_uart_messages_proto_rawDescGZIP(), []int{39} + return file_uart_messages_proto_rawDescGZIP(), []int{41} } func (x *OtaSlaveProgressResponse) GetActive() bool { @@ -3156,7 +3316,7 @@ var File_uart_messages_proto protoreflect.FileDescriptor const file_uart_messages_proto_rawDesc = "" + "\n" + - "\x13uart_messages.proto\x12\x04alox\x1a\fnanopb.proto\"\xec\x11\n" + + "\x13uart_messages.proto\x12\x04alox\x1a\fnanopb.proto\"\x9f\x13\n" + "\vUartMessage\x12%\n" + "\x04type\x18\x01 \x01(\x0e2\x11.alox.MessageTypeR\x04type\x12,\n" + "\vack_payload\x18\x02 \x01(\v2\t.alox.AckH\x00R\n" + @@ -3191,7 +3351,9 @@ const file_uart_messages_proto_rawDesc = "" + "\x12tap_notify_request\x18\x1d \x01(\v2\x16.alox.TapNotifyRequestH\x00R\x10tapNotifyRequest\x12I\n" + "\x13tap_notify_response\x18\x1e \x01(\v2\x17.alox.TapNotifyResponseH\x00R\x11tapNotifyResponse\x12L\n" + "\x14cache_status_request\x18! \x01(\v2\x18.alox.CacheStatusRequestH\x00R\x12cacheStatusRequest\x12O\n" + - "\x15cache_status_response\x18\" \x01(\v2\x19.alox.CacheStatusResponseH\x00R\x13cacheStatusResponseB\t\n" + + "\x15cache_status_response\x18\" \x01(\v2\x19.alox.CacheStatusResponseH\x00R\x13cacheStatusResponse\x12V\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\x16espnowEchoPingResponseB\t\n" + "\apayload\"\x05\n" + "\x03Ack\"!\n" + "\vEchoPayload\x12\x12\n" + @@ -3311,7 +3473,16 @@ const file_uart_messages_proto_rawDesc = "" + "\x03seq\x18\x02 \x01(\rR\x03seq\"G\n" + "\x19EspNowUnicastTestResponse\x12\x18\n" + "\asuccess\x18\x01 \x01(\bR\asuccess\x12\x10\n" + - "\x03seq\x18\x02 \x01(\rR\x03seq\"\xc1\x02\n" + + "\x03seq\x18\x02 \x01(\rR\x03seq\"W\n" + + "\x15EspNowEchoPingRequest\x12\x1b\n" + + "\tclient_id\x18\x01 \x01(\rR\bclientId\x12!\n" + + "\ftimestamp_us\x18\x02 \x01(\x04R\vtimestampUs\"\x90\x01\n" + + "\x16EspNowEchoPingResponse\x12\x18\n" + + "\asuccess\x18\x01 \x01(\bR\asuccess\x12\x1b\n" + + "\tclient_id\x18\x02 \x01(\rR\bclientId\x12!\n" + + "\ftimestamp_us\x18\x03 \x01(\x04R\vtimestampUs\x12\x1c\n" + + "\n" + + "esp_rtt_us\x18\x04 \x01(\rR\bespRttUs\"\xc1\x02\n" + "\x16LedRingProgressRequest\x12\x12\n" + "\x04mode\x18\x01 \x01(\rR\x04mode\x12\x1a\n" + "\bprogress\x18\x02 \x01(\rR\bprogress\x12\x14\n" + @@ -3376,7 +3547,7 @@ const file_uart_messages_proto_rawDesc = "" + "\x0faggregate_bytes\x18\x03 \x01(\rR\x0eaggregateBytes\x12\x1f\n" + "\vslave_count\x18\x04 \x01(\rR\n" + "slaveCount\x12:\n" + - "\x06slaves\x18\x05 \x03(\v2\x1b.alox.OtaSlaveProgressEntryB\x05\x92?\x02\x10\x10R\x06slaves*\xf1\x02\n" + + "\x06slaves\x18\x05 \x03(\v2\x1b.alox.OtaSlaveProgressEntryB\x05\x92?\x02\x10\x10R\x06slaves*\x87\x03\n" + "\vMessageType\x12\v\n" + "\aUNKNOWN\x10\x00\x12\a\n" + "\x03ACK\x10\x01\x12\b\n" + @@ -3400,7 +3571,8 @@ const file_uart_messages_proto_rawDesc = "" + "\x0eBATTERY_STATUS\x10\x1a\x12\x0e\n" + "\n" + "TAP_NOTIFY\x10\x1b\x12\x10\n" + - "\fCACHE_STATUS\x10\x1d\"\x04\b\x18\x10\x18\"\x04\b\x1c\x10\x1c*G\n" + + "\fCACHE_STATUS\x10\x1d\x12\x14\n" + + "\x10ESPNOW_ECHO_PING\x10\x1e\"\x04\b\x18\x10\x18\"\x04\b\x1c\x10\x1c*G\n" + "\aTapKind\x12\f\n" + "\bTAP_NONE\x10\x00\x12\x0e\n" + "\n" + @@ -3423,7 +3595,7 @@ func file_uart_messages_proto_rawDescGZIP() []byte { } var file_uart_messages_proto_enumTypes = make([]protoimpl.EnumInfo, 2) -var file_uart_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 40) +var file_uart_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 42) var file_uart_messages_proto_goTypes = []any{ (MessageType)(0), // 0: alox.MessageType (TapKind)(0), // 1: alox.TapKind @@ -3454,19 +3626,21 @@ var file_uart_messages_proto_goTypes = []any{ (*CacheStatusResponse)(nil), // 26: alox.CacheStatusResponse (*EspNowUnicastTestRequest)(nil), // 27: alox.EspNowUnicastTestRequest (*EspNowUnicastTestResponse)(nil), // 28: alox.EspNowUnicastTestResponse - (*LedRingProgressRequest)(nil), // 29: alox.LedRingProgressRequest - (*LedRingProgressResponse)(nil), // 30: alox.LedRingProgressResponse - (*EspNowFindMeRequest)(nil), // 31: alox.EspNowFindMeRequest - (*EspNowFindMeResponse)(nil), // 32: alox.EspNowFindMeResponse - (*RestartRequest)(nil), // 33: alox.RestartRequest - (*RestartResponse)(nil), // 34: alox.RestartResponse - (*OtaStartPayload)(nil), // 35: alox.OtaStartPayload - (*OtaPayload)(nil), // 36: alox.OtaPayload - (*OtaEndPayload)(nil), // 37: alox.OtaEndPayload - (*OtaStatusPayload)(nil), // 38: alox.OtaStatusPayload - (*OtaSlaveProgressRequest)(nil), // 39: alox.OtaSlaveProgressRequest - (*OtaSlaveProgressEntry)(nil), // 40: alox.OtaSlaveProgressEntry - (*OtaSlaveProgressResponse)(nil), // 41: alox.OtaSlaveProgressResponse + (*EspNowEchoPingRequest)(nil), // 29: alox.EspNowEchoPingRequest + (*EspNowEchoPingResponse)(nil), // 30: alox.EspNowEchoPingResponse + (*LedRingProgressRequest)(nil), // 31: alox.LedRingProgressRequest + (*LedRingProgressResponse)(nil), // 32: alox.LedRingProgressResponse + (*EspNowFindMeRequest)(nil), // 33: alox.EspNowFindMeRequest + (*EspNowFindMeResponse)(nil), // 34: alox.EspNowFindMeResponse + (*RestartRequest)(nil), // 35: alox.RestartRequest + (*RestartResponse)(nil), // 36: alox.RestartResponse + (*OtaStartPayload)(nil), // 37: alox.OtaStartPayload + (*OtaPayload)(nil), // 38: alox.OtaPayload + (*OtaEndPayload)(nil), // 39: alox.OtaEndPayload + (*OtaStatusPayload)(nil), // 40: alox.OtaStatusPayload + (*OtaSlaveProgressRequest)(nil), // 41: alox.OtaSlaveProgressRequest + (*OtaSlaveProgressEntry)(nil), // 42: alox.OtaSlaveProgressEntry + (*OtaSlaveProgressResponse)(nil), // 43: alox.OtaSlaveProgressResponse } var file_uart_messages_proto_depIdxs = []int32{ 0, // 0: alox.UartMessage.type:type_name -> alox.MessageType @@ -3475,22 +3649,22 @@ var file_uart_messages_proto_depIdxs = []int32{ 5, // 3: alox.UartMessage.version_response:type_name -> alox.VersionResponse 7, // 4: alox.UartMessage.client_info_response:type_name -> alox.ClientInfoResponse 9, // 5: alox.UartMessage.client_input_response:type_name -> alox.ClientInputResponse - 35, // 6: alox.UartMessage.ota_start:type_name -> alox.OtaStartPayload - 36, // 7: alox.UartMessage.ota_payload:type_name -> alox.OtaPayload - 37, // 8: alox.UartMessage.ota_end:type_name -> alox.OtaEndPayload - 38, // 9: alox.UartMessage.ota_status:type_name -> alox.OtaStatusPayload + 37, // 6: alox.UartMessage.ota_start:type_name -> alox.OtaStartPayload + 38, // 7: alox.UartMessage.ota_payload:type_name -> alox.OtaPayload + 39, // 8: alox.UartMessage.ota_end:type_name -> alox.OtaEndPayload + 40, // 9: alox.UartMessage.ota_status:type_name -> alox.OtaStatusPayload 10, // 10: alox.UartMessage.accel_deadzone_request:type_name -> alox.AccelDeadzoneRequest 11, // 11: alox.UartMessage.accel_deadzone_response:type_name -> alox.AccelDeadzoneResponse 27, // 12: alox.UartMessage.espnow_unicast_test_request:type_name -> alox.EspNowUnicastTestRequest 28, // 13: alox.UartMessage.espnow_unicast_test_response:type_name -> alox.EspNowUnicastTestResponse - 39, // 14: alox.UartMessage.ota_slave_progress_request:type_name -> alox.OtaSlaveProgressRequest - 41, // 15: alox.UartMessage.ota_slave_progress_response:type_name -> alox.OtaSlaveProgressResponse - 29, // 16: alox.UartMessage.led_ring_progress_request:type_name -> alox.LedRingProgressRequest - 30, // 17: alox.UartMessage.led_ring_progress_response:type_name -> alox.LedRingProgressResponse - 31, // 18: alox.UartMessage.espnow_find_me_request:type_name -> alox.EspNowFindMeRequest - 32, // 19: alox.UartMessage.espnow_find_me_response:type_name -> alox.EspNowFindMeResponse - 33, // 20: alox.UartMessage.restart_request:type_name -> alox.RestartRequest - 34, // 21: alox.UartMessage.restart_response:type_name -> alox.RestartResponse + 41, // 14: alox.UartMessage.ota_slave_progress_request:type_name -> alox.OtaSlaveProgressRequest + 43, // 15: alox.UartMessage.ota_slave_progress_response:type_name -> alox.OtaSlaveProgressResponse + 31, // 16: alox.UartMessage.led_ring_progress_request:type_name -> alox.LedRingProgressRequest + 32, // 17: alox.UartMessage.led_ring_progress_response:type_name -> alox.LedRingProgressResponse + 33, // 18: alox.UartMessage.espnow_find_me_request:type_name -> alox.EspNowFindMeRequest + 34, // 19: alox.UartMessage.espnow_find_me_response:type_name -> alox.EspNowFindMeResponse + 35, // 20: alox.UartMessage.restart_request:type_name -> alox.RestartRequest + 36, // 21: alox.UartMessage.restart_response:type_name -> alox.RestartResponse 12, // 22: alox.UartMessage.accel_stream_request:type_name -> alox.AccelStreamRequest 13, // 23: alox.UartMessage.accel_stream_response:type_name -> alox.AccelStreamResponse 14, // 24: alox.UartMessage.battery_status_request:type_name -> alox.BatteryStatusRequest @@ -3499,22 +3673,24 @@ var file_uart_messages_proto_depIdxs = []int32{ 20, // 27: alox.UartMessage.tap_notify_response:type_name -> alox.TapNotifyResponse 22, // 28: alox.UartMessage.cache_status_request:type_name -> alox.CacheStatusRequest 26, // 29: alox.UartMessage.cache_status_response:type_name -> alox.CacheStatusResponse - 6, // 30: alox.ClientInfoResponse.clients:type_name -> alox.ClientInfo - 8, // 31: alox.ClientInputResponse.clients:type_name -> alox.ClientInput - 15, // 32: alox.BatterySample.lipo1:type_name -> alox.LipoReading - 15, // 33: alox.BatterySample.lipo2:type_name -> alox.LipoReading - 16, // 34: alox.BatteryStatusResponse.samples:type_name -> alox.BatterySample - 1, // 35: alox.TapEvent.kind:type_name -> alox.TapKind - 1, // 36: alox.CacheClientTap.kind:type_name -> alox.TapKind - 23, // 37: alox.CacheClientStatus.accel:type_name -> alox.CacheClientAccel - 24, // 38: alox.CacheClientStatus.tap:type_name -> alox.CacheClientTap - 25, // 39: alox.CacheStatusResponse.clients:type_name -> alox.CacheClientStatus - 40, // 40: alox.OtaSlaveProgressResponse.slaves:type_name -> alox.OtaSlaveProgressEntry - 41, // [41:41] is the sub-list for method output_type - 41, // [41:41] is the sub-list for method input_type - 41, // [41:41] is the sub-list for extension type_name - 41, // [41:41] is the sub-list for extension extendee - 0, // [0:41] is the sub-list for field type_name + 29, // 30: alox.UartMessage.espnow_echo_ping_request:type_name -> alox.EspNowEchoPingRequest + 30, // 31: alox.UartMessage.espnow_echo_ping_response:type_name -> alox.EspNowEchoPingResponse + 6, // 32: alox.ClientInfoResponse.clients:type_name -> alox.ClientInfo + 8, // 33: alox.ClientInputResponse.clients:type_name -> alox.ClientInput + 15, // 34: alox.BatterySample.lipo1:type_name -> alox.LipoReading + 15, // 35: alox.BatterySample.lipo2:type_name -> alox.LipoReading + 16, // 36: alox.BatteryStatusResponse.samples:type_name -> alox.BatterySample + 1, // 37: alox.TapEvent.kind:type_name -> alox.TapKind + 1, // 38: alox.CacheClientTap.kind:type_name -> alox.TapKind + 23, // 39: alox.CacheClientStatus.accel:type_name -> alox.CacheClientAccel + 24, // 40: alox.CacheClientStatus.tap:type_name -> alox.CacheClientTap + 25, // 41: alox.CacheStatusResponse.clients:type_name -> alox.CacheClientStatus + 42, // 42: alox.OtaSlaveProgressResponse.slaves:type_name -> alox.OtaSlaveProgressEntry + 43, // [43:43] is the sub-list for method output_type + 43, // [43:43] is the sub-list for method input_type + 43, // [43:43] is the sub-list for extension type_name + 43, // [43:43] is the sub-list for extension extendee + 0, // [0:43] is the sub-list for field type_name } func init() { file_uart_messages_proto_init() } @@ -3552,6 +3728,8 @@ func file_uart_messages_proto_init() { (*UartMessage_TapNotifyResponse)(nil), (*UartMessage_CacheStatusRequest)(nil), (*UartMessage_CacheStatusResponse)(nil), + (*UartMessage_EspnowEchoPingRequest)(nil), + (*UartMessage_EspnowEchoPingResponse)(nil), } type x struct{} out := protoimpl.TypeBuilder{ @@ -3559,7 +3737,7 @@ func file_uart_messages_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_uart_messages_proto_rawDesc), len(file_uart_messages_proto_rawDesc)), NumEnums: 2, - NumMessages: 40, + NumMessages: 42, NumExtensions: 0, NumServices: 0, }, diff --git a/goTool/webui/index.html b/goTool/webui/index.html index 070241f..dfa74cb 100644 --- a/goTool/webui/index.html +++ b/goTool/webui/index.html @@ -403,6 +403,12 @@ title="ESP-NOW Unicast-Test"> Test +