From 490e0ee61f03c70f36626e844a596608c842b400 Mon Sep 17 00:00:00 2001 From: simon Date: Sat, 6 Jun 2026 18:03:34 +0200 Subject: [PATCH] Add UART SET_LOG_LEVEL for runtime master ESP-IDF logging. Expose the command via goTool CLI/REST and dashboard controls so log verbosity can be tuned without reflashing. Co-authored-by: Cursor --- docs/ARCHITECTURE.md | 2 +- docs/DOCUMENTATION.md | 31 +++- docs/adding-a-feature.md | 2 +- goTool/README.md | 5 + goTool/api_serve.go | 58 +++++++ goTool/client_api.go | 10 ++ goTool/cmd_log_level.go | 61 ++++++++ goTool/docs/API_REST.md | 34 +++++ goTool/main.go | 7 +- goTool/pb/uart_messages.pb.go | 271 ++++++++++++++++++++++++++------- goTool/webui/index.html | 71 +++++++++ main/CMakeLists.txt | 1 + main/README.md | 27 ++++ main/cmd/cmd_handler.c | 2 + main/cmd/cmd_set_log_level.c | 51 +++++++ main/cmd/cmd_set_log_level.h | 6 + main/powerpod.c | 5 +- main/proto/uart_messages.pb.c | 6 + main/proto/uart_messages.pb.h | 58 ++++++- main/proto/uart_messages.proto | 16 ++ 20 files changed, 655 insertions(+), 69 deletions(-) create mode 100644 goTool/cmd_log_level.go create mode 100644 main/cmd/cmd_set_log_level.c create mode 100644 main/cmd/cmd_set_log_level.h diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 7cea06c..f7c3f9a 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -207,7 +207,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_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`. +**Nur Master / nur Cache (kein Slave-Roundtrip):** `cmd_client_info.c`, `cmd_battery.c`, `cmd_cache_status.c`, `cmd_version.c`, `cmd_set_log_level.c`. --- diff --git a/docs/DOCUMENTATION.md b/docs/DOCUMENTATION.md index 58719e9..dd41048 100644 --- a/docs/DOCUMENTATION.md +++ b/docs/DOCUMENTATION.md @@ -54,7 +54,9 @@ Zielbild für den Host: Befehle an den Master senden; der Master steuert Slaves | LiPo ADC 1 | 1 | `board_input.c` | | LiPo ADC 2 | 12 | Entfällt wenn = Taster-GPIO | -**UART:** `UART_NUM_1`, **921600** Baud, 8N1, kein Flow-Control. +**UART (Host-Protokoll):** `UART_NUM_1`, **921600** Baud, 8N1, kein Flow-Control. + +**ESP-IDF-Log (Debug):** `esp_log_*` geht auf **UART0** (Standard-Konsole, typisch USB am Dev-Board, **115200** Baud, `CONFIG_ESP_CONSOLE_UART_NUM=0`). Das ist **getrennt** vom Host-UART1 — goTool liest keine `esp_log`-Ausgabe. Ohne angeschlossenes Debug-Kabel werden aktivierte Logs trotzdem formatiert und an UART0 gesendet (CPU-Overhead bleibt); nur `ESP_LOG_NONE` / Level-Filter vermeiden die Arbeit. **I2C:** 100 kHz, interne Pull-ups, gemeinsamer Bus für Expander und BMA456H. @@ -233,6 +235,7 @@ Nur auf dem **Master** registriert (`powerpod.c`). IDs aus `MessageType` in `uar | 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) | +| 31 | SET_LOG_LEVEL | `cmd_set_log_level.c` | ESP-IDF-Log-Level global (`"*"`) lesen/setzen | ### 7.1 VERSION (3) @@ -316,6 +319,28 @@ Round-Trip-Latenztest zu einem **Slave** (`client_id` > 0, muss in der Registry **Host-seitig (goTool):** `rtt_ms` = volle UART-Kette (Send bis Response-Empfang); unabhängig von `esp_rtt_us`. +### 7.12 SET_LOG_LEVEL (31) + +Laufzeit-Steuerung des **globalen** ESP-IDF-Log-Levels auf dem Master (`esp_log_level_set("*", …)`). Kein ESP-NOW, kein NVS — nur Master. + +**Request:** `write`, `level` (`esp_log_level_t`: 0=NONE, 1=ERROR, 2=WARN, 3=INFO, 4=DEBUG, 5=VERBOSE). + +| `write` | Verhalten | +|---------|-----------| +| `false` / leer | Aktuelles Level lesen (`esp_log_level_get("*")`) | +| `true` | Level setzen; ungültige Werte (>5) → `success=false` | + +**Response:** `success`, `level` (aktuell bzw. gesetzt). + +**Boot-Default:** `CONFIG_LOG_DEFAULT_LEVEL` in `sdkconfig` (aktuell **INFO** = 3). Kann per UART/Web-UI zur Laufzeit geändert werden; nach Reboot gilt wieder der sdkconfig-Wert. + +**Ausgabe:** Logs erscheinen auf **UART0** (Debug-USB), nicht auf dem Host-UART1 (goTool). + +```bash +go run . -port /dev/ttyUSB0 log-level +go run . -port /dev/ttyUSB0 log-level -set -level 3 +``` + --- ## 8. OTA @@ -457,6 +482,7 @@ Includes in generierten `.pb.c` müssen `"uart_messages.pb.h"` heißen (nicht `m | `cmd_restart.c` | RESTART | | `cmd_espnow_unicast_test.c` | ESPNOW_UNICAST_TEST | | `cmd_espnow_echo_ping.c` | ESPNOW_ECHO_PING | +| `cmd_set_log_level.c` | SET_LOG_LEVEL | | `cmd_ota.c` | OTA_* | | `cmd_ota_slave_progress.c` | OTA_SLAVE_PROGRESS | @@ -485,9 +511,12 @@ Includes in generierten `.pb.c` müssen `"uart_messages.pb.h"` heißen (nicht `m ## 15. Logging-Tags +**Level zur Laufzeit:** UART `SET_LOG_LEVEL` (31) oder Dashboard „ESP Log-Level“ — steuert nur die Konsolen-Ausgabe auf UART0, nicht das Host-Protokoll. + | Tag | Modul | |-----|--------| | `[Main]` | powerpod.c | +| `[LOG_LVL]` | cmd_set_log_level.c | | `[UART]` | uart.c | | `[CMDH]` | cmd_handler.c | | `[UART_CMD]` | uart_cmd.c | diff --git a/docs/adding-a-feature.md b/docs/adding-a-feature.md index 5fc2609..9c5d798 100644 --- a/docs/adding-a-feature.md +++ b/docs/adding-a-feature.md @@ -345,7 +345,7 @@ idf.py build Ähnliche Features zum Abgucken: -- **Nur Master, kein ESP-NOW:** `main/cmd/cmd_version.c`, `main/cmd/cmd_led_ring.c` +- **Nur Master, kein ESP-NOW:** `main/cmd/cmd_version.c`, `main/cmd/cmd_led_ring.c`, `main/cmd/cmd_set_log_level.c` - **Nur Slave per ESP-NOW (Master leitet nur durch):** `main/cmd/cmd_espnow_unicast_test.c` - **Master + alle Slaves / Filter:** `main/cmd/cmd_accel_deadzone.c` - **Großer ESP-NOW-Fluss mit Status:** `ota_espnow.c`, `main/cmd/cmd_ota.c` diff --git a/goTool/README.md b/goTool/README.md index e2172fb..4a6b1c4 100644 --- a/goTool/README.md +++ b/goTool/README.md @@ -36,6 +36,7 @@ go run . -port /dev/ttyUSB0 clients | `led-ring` | 8 | LED ring: `-mode clear\|color\|progress\|digit\|blink\|find-me`, `-client`, `-all` | | `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 | `clients` requires slaves to have responded to master discover broadcasts first. @@ -116,8 +117,12 @@ On success the slave serial log should show `UNICAST TEST OK from master … seq ```bash go run . -port /dev/ttyUSB0 echo-ping -client 16 +go run . -port /dev/ttyUSB0 log-level +go run . -port /dev/ttyUSB0 log-level -set -level 3 ``` +`log-level` controls `esp_log_*` on the master (UART0 USB console). The host protocol UART (GPIO 2/3) is unchanged. + 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: diff --git a/goTool/api_serve.go b/goTool/api_serve.go index 1d0e533..9f81c2b 100644 --- a/goTool/api_serve.go +++ b/goTool/api_serve.go @@ -74,6 +74,17 @@ type restartAPIResponse struct { Error string `json:"error,omitempty"` } +type logLevelAPIResponse struct { + Success bool `json:"success"` + Level uint32 `json:"level"` + Error string `json:"error,omitempty"` +} + +type logLevelAPIRequest struct { + Write bool `json:"write"` + Level uint32 `json:"level"` +} + type otaAPIResponse struct { Success bool `json:"success"` BytesWritten uint32 `json:"bytes_written,omitempty"` @@ -125,6 +136,16 @@ func mountServeAPI(mux *http.ServeMux, link *managedSerial, hub *wsHub, streamCt } serveRestart(w, r, link) }) + mux.HandleFunc("/api/log-level", func(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case http.MethodGet: + serveLogLevelGet(w, r, link) + case http.MethodPost: + serveLogLevelPost(w, r, link) + default: + http.Error(w, "method not allowed", http.StatusMethodNotAllowed) + } + }) mux.HandleFunc("/api/ota", func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "method not allowed", http.StatusMethodNotAllowed) @@ -280,6 +301,43 @@ func applyDeadzoneToSlaves(link *managedSerial, deadzone uint32) (uint32, error) return updated, nil } +func serveLogLevelGet(w http.ResponseWriter, r *http.Request, link *managedSerial) { + resp, err := link.SetLogLevel(false, 0) + if err != nil { + writeJSON(w, http.StatusServiceUnavailable, logLevelAPIResponse{Error: err.Error()}) + return + } + writeJSON(w, http.StatusOK, logLevelAPIResponse{ + Success: resp.GetSuccess(), + Level: resp.GetLevel(), + }) +} + +func serveLogLevelPost(w http.ResponseWriter, r *http.Request, link *managedSerial) { + var body logLevelAPIRequest + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + writeJSON(w, http.StatusBadRequest, logLevelAPIResponse{Error: "invalid JSON"}) + return + } + if !body.Write { + writeJSON(w, http.StatusBadRequest, logLevelAPIResponse{Error: "write must be true"}) + return + } + if body.Level > 5 { + writeJSON(w, http.StatusBadRequest, logLevelAPIResponse{Error: "level must be 0–5"}) + return + } + resp, err := link.SetLogLevel(true, body.Level) + if err != nil { + writeJSON(w, http.StatusServiceUnavailable, logLevelAPIResponse{Error: err.Error()}) + return + } + writeJSON(w, http.StatusOK, logLevelAPIResponse{ + Success: resp.GetSuccess(), + Level: resp.GetLevel(), + }) +} + func serveRestart(w http.ResponseWriter, r *http.Request, link *managedSerial) { var body restartAPIRequest if err := json.NewDecoder(r.Body).Decode(&body); err != nil { diff --git a/goTool/client_api.go b/goTool/client_api.go index 63f3884..4fefd36 100644 --- a/goTool/client_api.go +++ b/goTool/client_api.go @@ -477,6 +477,16 @@ func (m *managedSerial) FindMe(clientID uint32) error { }) } +func (m *managedSerial) SetLogLevel(write bool, level uint32) (*pb.SetLogLevelResponse, error) { + var resp *pb.SetLogLevelResponse + err := m.withPort(func(sp *serialPort) error { + var e error + resp, e = runSetLogLevelClient(sp, write, level) + return e + }) + return resp, err +} + func (m *managedSerial) Restart(clientID uint32) error { err := m.withPort(func(sp *serialPort) error { return runRestartClient(sp, clientID) diff --git a/goTool/cmd_log_level.go b/goTool/cmd_log_level.go new file mode 100644 index 0000000..aac1d8d --- /dev/null +++ b/goTool/cmd_log_level.go @@ -0,0 +1,61 @@ +package main + +import ( + "flag" + "fmt" + + "google.golang.org/protobuf/proto" + "powerpod/gotool/pb" +) + +func runLogLevel(sp *serialPort, args []string) error { + fs := flag.NewFlagSet("log-level", flag.ExitOnError) + write := fs.Bool("set", false, "write log level (default: read)") + level := fs.Uint("level", 0, "esp_log_level_t 0–5 (with -set)") + if err := fs.Parse(args); err != nil { + return err + } + resp, err := sp.setLogLevel(*write, uint32(*level)) + if err != nil { + return err + } + if !resp.GetSuccess() { + return fmt.Errorf("set_log_level rejected (level=%d)", resp.GetLevel()) + } + fmt.Printf("log_level=%d success=%v\n", resp.GetLevel(), resp.GetSuccess()) + return nil +} + +func runSetLogLevelClient(sp *serialPort, write bool, level uint32) (*pb.SetLogLevelResponse, error) { + return sp.setLogLevel(write, level) +} + +func (s *serialPort) setLogLevel(write bool, level uint32) (*pb.SetLogLevelResponse, error) { + msg := &pb.UartMessage{ + Type: pb.MessageType_SET_LOG_LEVEL, + Payload: &pb.UartMessage_SetLogLevelRequest{ + SetLogLevelRequest: &pb.SetLogLevelRequest{ + Write: write, + Level: level, + }, + }, + } + body, err := proto.Marshal(msg) + if err != nil { + return nil, fmt.Errorf("encode: %w", err) + } + payload := append([]byte{byte(pb.MessageType_SET_LOG_LEVEL)}, body...) + respPayload, err := s.exchangePayload(payload, "SET_LOG_LEVEL") + 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.GetSetLogLevelResponse() + if r == nil { + return nil, fmt.Errorf("missing set_log_level_response") + } + return r, nil +} diff --git a/goTool/docs/API_REST.md b/goTool/docs/API_REST.md index 87bc3c7..963c0dc 100644 --- a/goTool/docs/API_REST.md +++ b/goTool/docs/API_REST.md @@ -282,6 +282,39 @@ Content-Type: application/json {"client_id": 16} ``` +### Log level (master ESP-IDF console) + +Runtime get/set of the **global** log filter on the master (`esp_log_level_set("*", …)`). Output goes to **UART0** (USB debug, 115200), not the host protocol UART (GPIO 2/3, 921600). + +```http +GET /api/log-level +POST /api/log-level +Content-Type: application/json +{"write": true, "level": 3} +``` + +| `level` | Meaning | +|---------|---------| +| 0 | None (no log output) | +| 1 | Error | +| 2 | Warn | +| 3 | Info | +| 4 | Debug | +| 5 | Verbose | + +```json +{"success": true, "level": 3} +``` + +**CLI:** + +```bash +go run . -port /dev/ttyUSB0 log-level +go run . -port /dev/ttyUSB0 log-level -set -level 3 +``` + +Dashboard: Master card → dropdown **ESP Log-Level** with **Lesen** / **Setzen**. + ### OTA (master UART upload) ```http @@ -329,5 +362,6 @@ Same as external API: | 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) | +| Master log level | `GET` / `POST /api/log-level` or CLI `log-level` | | 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/main.go b/goTool/main.go index 47f7188..b468c46 100644 --- a/goTool/main.go +++ b/goTool/main.go @@ -26,7 +26,8 @@ func usage() { fmt.Fprintf(os.Stderr, " ota-progress query per-slave ESP-NOW OTA progress on master\n") 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\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") flag.PrintDefaults() } @@ -53,7 +54,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", "echo-ping", "echo_ping", "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", "log-level", "log_level", "ota", "ota-progress", "ota_progress": if *portName == "" { fmt.Fprintf(os.Stderr, "command %q requires -port\n\n", cmd) usage() @@ -87,6 +88,8 @@ func main() { runErr = runFindMe(sp, flag.Args()[1:]) case "restart": runErr = runRestart(sp, flag.Args()[1:]) + case "log-level", "log_level": + runErr = runLogLevel(sp, flag.Args()[1:]) case "ota": runErr = runOTA(sp, flag.Args()[1:]) case "ota-progress", "ota_progress": diff --git a/goTool/pb/uart_messages.pb.go b/goTool/pb/uart_messages.pb.go index 9735604..b9e545b 100644 --- a/goTool/pb/uart_messages.pb.go +++ b/goTool/pb/uart_messages.pb.go @@ -48,6 +48,8 @@ const ( MessageType_CACHE_STATUS MessageType = 29 // * Host → master → slave → master: timestamp echo round-trip (latency test). MessageType_ESPNOW_ECHO_PING MessageType = 30 + // * Host → master: get/set ESP-IDF log level for tag "*" (global). + MessageType_SET_LOG_LEVEL MessageType = 31 ) // Enum value maps for MessageType. @@ -75,6 +77,7 @@ var ( 27: "TAP_NOTIFY", 29: "CACHE_STATUS", 30: "ESPNOW_ECHO_PING", + 31: "SET_LOG_LEVEL", } MessageType_value = map[string]int32{ "UNKNOWN": 0, @@ -99,6 +102,7 @@ var ( "TAP_NOTIFY": 27, "CACHE_STATUS": 29, "ESPNOW_ECHO_PING": 30, + "SET_LOG_LEVEL": 31, } ) @@ -217,6 +221,8 @@ type UartMessage struct { // *UartMessage_CacheStatusResponse // *UartMessage_EspnowEchoPingRequest // *UartMessage_EspnowEchoPingResponse + // *UartMessage_SetLogLevelRequest + // *UartMessage_SetLogLevelResponse Payload isUartMessage_Payload `protobuf_oneof:"payload"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -545,6 +551,24 @@ func (x *UartMessage) GetEspnowEchoPingResponse() *EspNowEchoPingResponse { return nil } +func (x *UartMessage) GetSetLogLevelRequest() *SetLogLevelRequest { + if x != nil { + if x, ok := x.Payload.(*UartMessage_SetLogLevelRequest); ok { + return x.SetLogLevelRequest + } + } + return nil +} + +func (x *UartMessage) GetSetLogLevelResponse() *SetLogLevelResponse { + if x != nil { + if x, ok := x.Payload.(*UartMessage_SetLogLevelResponse); ok { + return x.SetLogLevelResponse + } + } + return nil +} + type isUartMessage_Payload interface { isUartMessage_Payload() } @@ -673,6 +697,14 @@ type UartMessage_EspnowEchoPingResponse struct { EspnowEchoPingResponse *EspNowEchoPingResponse `protobuf:"bytes,36,opt,name=espnow_echo_ping_response,json=espnowEchoPingResponse,proto3,oneof"` } +type UartMessage_SetLogLevelRequest struct { + SetLogLevelRequest *SetLogLevelRequest `protobuf:"bytes,37,opt,name=set_log_level_request,json=setLogLevelRequest,proto3,oneof"` +} + +type UartMessage_SetLogLevelResponse struct { + SetLogLevelResponse *SetLogLevelResponse `protobuf:"bytes,38,opt,name=set_log_level_response,json=setLogLevelResponse,proto3,oneof"` +} + func (*UartMessage_AckPayload) isUartMessage_Payload() {} func (*UartMessage_EchoPayload) isUartMessage_Payload() {} @@ -735,6 +767,10 @@ func (*UartMessage_EspnowEchoPingRequest) isUartMessage_Payload() {} func (*UartMessage_EspnowEchoPingResponse) isUartMessage_Payload() {} +func (*UartMessage_SetLogLevelRequest) isUartMessage_Payload() {} + +func (*UartMessage_SetLogLevelResponse) isUartMessage_Payload() {} + type Ack struct { state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields @@ -2909,6 +2945,112 @@ func (x *RestartResponse) GetClientId() uint32 { return 0 } +// * Host → master: read/write global log level (esp_log_level_set("*", …)). +type SetLogLevelRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Write bool `protobuf:"varint,1,opt,name=write,proto3" json:"write,omitempty"` + // * esp_log_level_t: 0=NONE, 1=ERROR, 2=WARN, 3=INFO, 4=DEBUG, 5=VERBOSE + Level uint32 `protobuf:"varint,2,opt,name=level,proto3" json:"level,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SetLogLevelRequest) Reset() { + *x = SetLogLevelRequest{} + mi := &file_uart_messages_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SetLogLevelRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetLogLevelRequest) ProtoMessage() {} + +func (x *SetLogLevelRequest) ProtoReflect() protoreflect.Message { + mi := &file_uart_messages_proto_msgTypes[35] + 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 SetLogLevelRequest.ProtoReflect.Descriptor instead. +func (*SetLogLevelRequest) Descriptor() ([]byte, []int) { + return file_uart_messages_proto_rawDescGZIP(), []int{35} +} + +func (x *SetLogLevelRequest) GetWrite() bool { + if x != nil { + return x.Write + } + return false +} + +func (x *SetLogLevelRequest) GetLevel() uint32 { + if x != nil { + return x.Level + } + return 0 +} + +type SetLogLevelResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"` + Level uint32 `protobuf:"varint,2,opt,name=level,proto3" json:"level,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SetLogLevelResponse) Reset() { + *x = SetLogLevelResponse{} + mi := &file_uart_messages_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SetLogLevelResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetLogLevelResponse) ProtoMessage() {} + +func (x *SetLogLevelResponse) ProtoReflect() protoreflect.Message { + mi := &file_uart_messages_proto_msgTypes[36] + 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 SetLogLevelResponse.ProtoReflect.Descriptor instead. +func (*SetLogLevelResponse) Descriptor() ([]byte, []int) { + return file_uart_messages_proto_rawDescGZIP(), []int{36} +} + +func (x *SetLogLevelResponse) GetSuccess() bool { + if x != nil { + return x.Success + } + return false +} + +func (x *SetLogLevelResponse) GetLevel() uint32 { + if x != nil { + return x.Level + } + return 0 +} + // Host → device: begin UART OTA (erase inactive OTA slot; device replies OTA_STATUS). type OtaStartPayload struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -2919,7 +3061,7 @@ type OtaStartPayload struct { func (x *OtaStartPayload) Reset() { *x = OtaStartPayload{} - mi := &file_uart_messages_proto_msgTypes[35] + mi := &file_uart_messages_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2931,7 +3073,7 @@ func (x *OtaStartPayload) String() string { func (*OtaStartPayload) ProtoMessage() {} func (x *OtaStartPayload) 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 { @@ -2944,7 +3086,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{35} + return file_uart_messages_proto_rawDescGZIP(), []int{37} } func (x *OtaStartPayload) GetTotalSize() uint32 { @@ -2965,7 +3107,7 @@ type OtaPayload struct { func (x *OtaPayload) Reset() { *x = OtaPayload{} - mi := &file_uart_messages_proto_msgTypes[36] + mi := &file_uart_messages_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2977,7 +3119,7 @@ func (x *OtaPayload) String() string { func (*OtaPayload) ProtoMessage() {} func (x *OtaPayload) 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 { @@ -2990,7 +3132,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{36} + return file_uart_messages_proto_rawDescGZIP(), []int{38} } func (x *OtaPayload) GetSeq() uint32 { @@ -3016,7 +3158,7 @@ type OtaEndPayload struct { func (x *OtaEndPayload) Reset() { *x = OtaEndPayload{} - mi := &file_uart_messages_proto_msgTypes[37] + mi := &file_uart_messages_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3028,7 +3170,7 @@ func (x *OtaEndPayload) String() string { func (*OtaEndPayload) ProtoMessage() {} func (x *OtaEndPayload) 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 { @@ -3041,7 +3183,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{37} + return file_uart_messages_proto_rawDescGZIP(), []int{39} } // Device → host status (also used as ACK after each 4 KiB written). @@ -3058,7 +3200,7 @@ type OtaStatusPayload struct { func (x *OtaStatusPayload) Reset() { *x = OtaStatusPayload{} - mi := &file_uart_messages_proto_msgTypes[38] + mi := &file_uart_messages_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3070,7 +3212,7 @@ func (x *OtaStatusPayload) String() string { func (*OtaStatusPayload) ProtoMessage() {} func (x *OtaStatusPayload) 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 { @@ -3083,7 +3225,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{38} + return file_uart_messages_proto_rawDescGZIP(), []int{40} } func (x *OtaStatusPayload) GetStatus() uint32 { @@ -3124,7 +3266,7 @@ type OtaSlaveProgressRequest struct { func (x *OtaSlaveProgressRequest) Reset() { *x = OtaSlaveProgressRequest{} - mi := &file_uart_messages_proto_msgTypes[39] + mi := &file_uart_messages_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3136,7 +3278,7 @@ func (x *OtaSlaveProgressRequest) String() string { func (*OtaSlaveProgressRequest) ProtoMessage() {} func (x *OtaSlaveProgressRequest) 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 { @@ -3149,7 +3291,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{39} + return file_uart_messages_proto_rawDescGZIP(), []int{41} } func (x *OtaSlaveProgressRequest) GetClientId() uint32 { @@ -3173,7 +3315,7 @@ type OtaSlaveProgressEntry struct { func (x *OtaSlaveProgressEntry) Reset() { *x = OtaSlaveProgressEntry{} - mi := &file_uart_messages_proto_msgTypes[40] + mi := &file_uart_messages_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3185,7 +3327,7 @@ func (x *OtaSlaveProgressEntry) String() string { func (*OtaSlaveProgressEntry) ProtoMessage() {} func (x *OtaSlaveProgressEntry) ProtoReflect() protoreflect.Message { - mi := &file_uart_messages_proto_msgTypes[40] + mi := &file_uart_messages_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3198,7 +3340,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{40} + return file_uart_messages_proto_rawDescGZIP(), []int{42} } func (x *OtaSlaveProgressEntry) GetClientId() uint32 { @@ -3249,7 +3391,7 @@ type OtaSlaveProgressResponse struct { func (x *OtaSlaveProgressResponse) Reset() { *x = OtaSlaveProgressResponse{} - mi := &file_uart_messages_proto_msgTypes[41] + mi := &file_uart_messages_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3261,7 +3403,7 @@ func (x *OtaSlaveProgressResponse) String() string { func (*OtaSlaveProgressResponse) ProtoMessage() {} func (x *OtaSlaveProgressResponse) ProtoReflect() protoreflect.Message { - mi := &file_uart_messages_proto_msgTypes[41] + mi := &file_uart_messages_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3274,7 +3416,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{41} + return file_uart_messages_proto_rawDescGZIP(), []int{43} } func (x *OtaSlaveProgressResponse) GetActive() bool { @@ -3316,7 +3458,7 @@ var File_uart_messages_proto protoreflect.FileDescriptor const file_uart_messages_proto_rawDesc = "" + "\n" + - "\x13uart_messages.proto\x12\x04alox\x1a\fnanopb.proto\"\x9f\x13\n" + + "\x13uart_messages.proto\x12\x04alox\x1a\fnanopb.proto\"\xc0\x14\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" + @@ -3353,7 +3495,9 @@ const file_uart_messages_proto_rawDesc = "" + "\x14cache_status_request\x18! \x01(\v2\x18.alox.CacheStatusRequestH\x00R\x12cacheStatusRequest\x12O\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" + + "\x19espnow_echo_ping_response\x18$ \x01(\v2\x1c.alox.EspNowEchoPingResponseH\x00R\x16espnowEchoPingResponse\x12M\n" + + "\x15set_log_level_request\x18% \x01(\v2\x18.alox.SetLogLevelRequestH\x00R\x12setLogLevelRequest\x12P\n" + + "\x16set_log_level_response\x18& \x01(\v2\x19.alox.SetLogLevelResponseH\x00R\x13setLogLevelResponseB\t\n" + "\apayload\"\x05\n" + "\x03Ack\"!\n" + "\vEchoPayload\x12\x12\n" + @@ -3516,7 +3660,13 @@ const file_uart_messages_proto_rawDesc = "" + "\tclient_id\x18\x01 \x01(\rR\bclientId\"H\n" + "\x0fRestartResponse\x12\x18\n" + "\asuccess\x18\x01 \x01(\bR\asuccess\x12\x1b\n" + - "\tclient_id\x18\x02 \x01(\rR\bclientId\"0\n" + + "\tclient_id\x18\x02 \x01(\rR\bclientId\"@\n" + + "\x12SetLogLevelRequest\x12\x14\n" + + "\x05write\x18\x01 \x01(\bR\x05write\x12\x14\n" + + "\x05level\x18\x02 \x01(\rR\x05level\"E\n" + + "\x13SetLogLevelResponse\x12\x18\n" + + "\asuccess\x18\x01 \x01(\bR\asuccess\x12\x14\n" + + "\x05level\x18\x02 \x01(\rR\x05level\"0\n" + "\x0fOtaStartPayload\x12\x1d\n" + "\n" + "total_size\x18\x01 \x01(\rR\ttotalSize\":\n" + @@ -3547,7 +3697,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*\x87\x03\n" + + "\x06slaves\x18\x05 \x03(\v2\x1b.alox.OtaSlaveProgressEntryB\x05\x92?\x02\x10\x10R\x06slaves*\x9a\x03\n" + "\vMessageType\x12\v\n" + "\aUNKNOWN\x10\x00\x12\a\n" + "\x03ACK\x10\x01\x12\b\n" + @@ -3572,7 +3722,8 @@ const file_uart_messages_proto_rawDesc = "" + "\n" + "TAP_NOTIFY\x10\x1b\x12\x10\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" + + "\x10ESPNOW_ECHO_PING\x10\x1e\x12\x11\n" + + "\rSET_LOG_LEVEL\x10\x1f\"\x04\b\x18\x10\x18\"\x04\b\x1c\x10\x1c*G\n" + "\aTapKind\x12\f\n" + "\bTAP_NONE\x10\x00\x12\x0e\n" + "\n" + @@ -3595,7 +3746,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, 42) +var file_uart_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 44) var file_uart_messages_proto_goTypes = []any{ (MessageType)(0), // 0: alox.MessageType (TapKind)(0), // 1: alox.TapKind @@ -3634,13 +3785,15 @@ var file_uart_messages_proto_goTypes = []any{ (*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 + (*SetLogLevelRequest)(nil), // 37: alox.SetLogLevelRequest + (*SetLogLevelResponse)(nil), // 38: alox.SetLogLevelResponse + (*OtaStartPayload)(nil), // 39: alox.OtaStartPayload + (*OtaPayload)(nil), // 40: alox.OtaPayload + (*OtaEndPayload)(nil), // 41: alox.OtaEndPayload + (*OtaStatusPayload)(nil), // 42: alox.OtaStatusPayload + (*OtaSlaveProgressRequest)(nil), // 43: alox.OtaSlaveProgressRequest + (*OtaSlaveProgressEntry)(nil), // 44: alox.OtaSlaveProgressEntry + (*OtaSlaveProgressResponse)(nil), // 45: alox.OtaSlaveProgressResponse } var file_uart_messages_proto_depIdxs = []int32{ 0, // 0: alox.UartMessage.type:type_name -> alox.MessageType @@ -3649,16 +3802,16 @@ 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 - 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 + 39, // 6: alox.UartMessage.ota_start:type_name -> alox.OtaStartPayload + 40, // 7: alox.UartMessage.ota_payload:type_name -> alox.OtaPayload + 41, // 8: alox.UartMessage.ota_end:type_name -> alox.OtaEndPayload + 42, // 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 - 41, // 14: alox.UartMessage.ota_slave_progress_request:type_name -> alox.OtaSlaveProgressRequest - 43, // 15: alox.UartMessage.ota_slave_progress_response:type_name -> alox.OtaSlaveProgressResponse + 43, // 14: alox.UartMessage.ota_slave_progress_request:type_name -> alox.OtaSlaveProgressRequest + 45, // 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 @@ -3675,22 +3828,24 @@ var file_uart_messages_proto_depIdxs = []int32{ 26, // 29: alox.UartMessage.cache_status_response:type_name -> alox.CacheStatusResponse 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 + 37, // 32: alox.UartMessage.set_log_level_request:type_name -> alox.SetLogLevelRequest + 38, // 33: alox.UartMessage.set_log_level_response:type_name -> alox.SetLogLevelResponse + 6, // 34: alox.ClientInfoResponse.clients:type_name -> alox.ClientInfo + 8, // 35: alox.ClientInputResponse.clients:type_name -> alox.ClientInput + 15, // 36: alox.BatterySample.lipo1:type_name -> alox.LipoReading + 15, // 37: alox.BatterySample.lipo2:type_name -> alox.LipoReading + 16, // 38: alox.BatteryStatusResponse.samples:type_name -> alox.BatterySample + 1, // 39: alox.TapEvent.kind:type_name -> alox.TapKind + 1, // 40: alox.CacheClientTap.kind:type_name -> alox.TapKind + 23, // 41: alox.CacheClientStatus.accel:type_name -> alox.CacheClientAccel + 24, // 42: alox.CacheClientStatus.tap:type_name -> alox.CacheClientTap + 25, // 43: alox.CacheStatusResponse.clients:type_name -> alox.CacheClientStatus + 44, // 44: alox.OtaSlaveProgressResponse.slaves:type_name -> alox.OtaSlaveProgressEntry + 45, // [45:45] is the sub-list for method output_type + 45, // [45:45] is the sub-list for method input_type + 45, // [45:45] is the sub-list for extension type_name + 45, // [45:45] is the sub-list for extension extendee + 0, // [0:45] is the sub-list for field type_name } func init() { file_uart_messages_proto_init() } @@ -3730,6 +3885,8 @@ func file_uart_messages_proto_init() { (*UartMessage_CacheStatusResponse)(nil), (*UartMessage_EspnowEchoPingRequest)(nil), (*UartMessage_EspnowEchoPingResponse)(nil), + (*UartMessage_SetLogLevelRequest)(nil), + (*UartMessage_SetLogLevelResponse)(nil), } type x struct{} out := protoimpl.TypeBuilder{ @@ -3737,7 +3894,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: 42, + NumMessages: 44, NumExtensions: 0, NumServices: 0, }, diff --git a/goTool/webui/index.html b/goTool/webui/index.html index dfa74cb..b307ccb 100644 --- a/goTool/webui/index.html +++ b/goTool/webui/index.html @@ -219,6 +219,8 @@
Deadzone
+
Log-Level
+
LiPo 1
LiPo 2
@@ -264,6 +266,31 @@ Restart + +
+ + + +

UART nicht verbunden — Eingabe gesperrt.

@@ -627,6 +654,7 @@ ws: null, wsConnected: false, masterDz: 100, + masterLogLevel: 0, allDz: 100, allTapSingle: false, allTapDouble: false, @@ -766,6 +794,11 @@ if (data.samples?.length) this.applyBatterySamples(data.samples); } catch (_) {} }, + formatLogLevel(level) { + const labels = ['None', 'Error', 'Warn', 'Info', 'Debug', 'Verbose']; + if (level == null || level < 0 || level > 5) return '—'; + return `${labels[level]} (${level})`; + }, formatMac(hex) { if (!hex || hex.length !== 12) return hex || ''; return hex.match(/.{2}/g).join(':'); @@ -1104,6 +1137,44 @@ async setMasterDeadzone() { await this.setDeadzone(0, this.masterDz); }, + async readMasterLogLevel() { + this.busy = true; + try { + const r = await fetch('/api/log-level'); + const data = await r.json(); + if (!r.ok || !data.success) { + this.flash(data.error || 'Log-Level lesen fehlgeschlagen', false); + return; + } + this.masterLogLevel = data.level; + this.flash(`Master: Log-Level ${this.formatLogLevel(data.level)}`, true); + } catch (e) { + this.flash(String(e), false); + } finally { + this.busy = false; + } + }, + async setMasterLogLevel() { + this.busy = true; + try { + const r = await fetch('/api/log-level', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ write: true, level: this.masterLogLevel }) + }); + const data = await r.json(); + if (!r.ok || !data.success) { + this.flash(data.error || 'Log-Level setzen fehlgeschlagen', false); + return; + } + this.masterLogLevel = data.level; + this.flash(`Master: Log-Level ${this.formatLogLevel(data.level)} gesetzt`, true); + } catch (e) { + this.flash(String(e), false); + } finally { + this.busy = false; + } + }, patchLiveStream(enabled) { let clients = this.state.clients || []; if (!enabled) { diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index dbe1ecc..6643a0b 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -28,6 +28,7 @@ idf_component_register( "pod_reboot.c" "cmd/cmd_led_ring.c" "cmd/cmd_battery.c" + "cmd/cmd_set_log_level.c" "cmd/cmd_ota.c" "cmd/cmd_ota_slave_progress.c" "ota_uart.c" diff --git a/main/README.md b/main/README.md index 4fec2fd..8e0c112 100644 --- a/main/README.md +++ b/main/README.md @@ -228,6 +228,8 @@ Host and master speak nanopb-encoded `UartMessage` inside UART frames (byte 0 = | 25 | `ACCEL_STREAM` | Implemented — enable/disable slave ESP-NOW accel stream to master | | 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) | +| 31 | `SET_LOG_LEVEL` | Implemented (`cmd/cmd_set_log_level.c`) — get/set global `esp_log_level_set("*", …)` on master | Regenerate C code: @@ -390,6 +392,30 @@ go run . -port /dev/ttyUSB0 find-me go run . -port /dev/ttyUSB0 find-me -client 16 ``` +### SET_LOG_LEVEL command + +Read or set the **global** ESP-IDF log filter on the master (`esp_log_level_set("*", level)`). Does not affect the host UART protocol (UART1); `esp_log_*` output goes to the **debug console UART0** (USB, 115200). + +**Request:** framed `31` (`0x1f`) + `set_log_level_request` (`write`, `level` 0–5). + +**Response:** `set_log_level_response` (`success`, `level`). + +| `level` | `esp_log_level_t` | +|---------|-------------------| +| 0 | NONE | +| 1 | ERROR | +| 2 | WARN | +| 3 | INFO | +| 4 | DEBUG | +| 5 | VERBOSE | + +Boot default follows `CONFIG_LOG_DEFAULT_LEVEL` in `sdkconfig` (not persisted across reboot). + +```bash +go run . -port /dev/ttyUSB0 log-level +go run . -port /dev/ttyUSB0 log-level -set -level 0 +``` + ### RESTART command Reboot the master (`client_id=0`) or one slave via ESP-NOW (`client_id` = registry id). The device sends the UART response, then restarts after ~150 ms. @@ -541,6 +567,7 @@ Target: ESP32-S3. Close serial monitor on the UART adapter port before running ` | `pod_settings.c/h` | NVS persistence (accel deadzone, …) | | `led_ring.c/h` | LED ring (digit display, progress bar) | | `cmd/cmd_led_ring.c` | UART `LED_RING` progress command | +| `cmd/cmd_set_log_level.c` | UART `SET_LOG_LEVEL` — runtime ESP-IDF log level | | `proto/uart_messages.proto` | UART protocol schema | | `proto/esp_now_messages.proto` | ESP-NOW protocol schema | | `esp_now_proto.c/h` | Encode/decode `EspNowMessage` | diff --git a/main/cmd/cmd_handler.c b/main/cmd/cmd_handler.c index d3dd9a5..0c7160a 100644 --- a/main/cmd/cmd_handler.c +++ b/main/cmd/cmd_handler.c @@ -59,6 +59,8 @@ static const char *message_type_name(uint16_t id) { return "CACHE_STATUS"; case alox_MessageType_ESPNOW_ECHO_PING: return "ESPNOW_ECHO_PING"; + case alox_MessageType_SET_LOG_LEVEL: + return "SET_LOG_LEVEL"; default: return "UNKNOWN"; } diff --git a/main/cmd/cmd_set_log_level.c b/main/cmd/cmd_set_log_level.c new file mode 100644 index 0000000..8517595 --- /dev/null +++ b/main/cmd/cmd_set_log_level.c @@ -0,0 +1,51 @@ +#include "cmd_set_log_level.h" +#include "esp_log.h" +#include "uart_cmd.h" + +static const char *TAG = "[LOG_LVL]"; + +static bool valid_level(uint32_t level) { return level <= ESP_LOG_VERBOSE; } + +static void reply(uint32_t level, bool success) { + alox_UartMessage response; + uart_cmd_init_response(&response, alox_MessageType_SET_LOG_LEVEL, + alox_UartMessage_set_log_level_response_tag); + response.payload.set_log_level_response.success = success; + response.payload.set_log_level_response.level = level; + uart_cmd_send(&response, TAG); +} + +static void handle_set_log_level(const uint8_t *data, size_t len) { + alox_UartMessage uart_msg; + alox_SetLogLevelRequest req = alox_SetLogLevelRequest_init_zero; + + if (uart_cmd_decode(data, len, &uart_msg) != ESP_OK) { + ESP_LOGW(TAG, "decode failed"); + reply((uint32_t)esp_log_level_get("*"), false); + return; + } + + const alox_SetLogLevelRequest *req_ptr = UART_CMD_REQ( + &uart_msg, alox_UartMessage_set_log_level_request_tag, set_log_level_request); + if (req_ptr != NULL) { + req = *req_ptr; + } + + if (req.write) { + if (!valid_level(req.level)) { + ESP_LOGW(TAG, "invalid level %lu", (unsigned long)req.level); + reply((uint32_t)esp_log_level_get("*"), false); + return; + } + esp_log_level_set("*", (esp_log_level_t)req.level); + ESP_LOGI(TAG, "global log level set to %lu", (unsigned long)req.level); + reply(req.level, true); + return; + } + + reply((uint32_t)esp_log_level_get("*"), true); +} + +void cmd_set_log_level_register(void) { + uart_cmd_register(alox_MessageType_SET_LOG_LEVEL, handle_set_log_level); +} diff --git a/main/cmd/cmd_set_log_level.h b/main/cmd/cmd_set_log_level.h new file mode 100644 index 0000000..dd72c81 --- /dev/null +++ b/main/cmd/cmd_set_log_level.h @@ -0,0 +1,6 @@ +#ifndef CMD_SET_LOG_LEVEL_H +#define CMD_SET_LOG_LEVEL_H + +void cmd_set_log_level_register(void); + +#endif diff --git a/main/powerpod.c b/main/powerpod.c index c30a317..0b72ff5 100644 --- a/main/powerpod.c +++ b/main/powerpod.c @@ -14,6 +14,7 @@ #include "cmd_ota_slave_progress.h" #include "cmd_led_ring.h" #include "cmd_battery.h" +#include "cmd_set_log_level.h" #include "esp_now_comm.h" #include "powerpod.h" #include "driver/gpio.h" @@ -73,9 +74,6 @@ uint8_t reverse_high_nibble_lut(uint8_t n) { } void app_main(void) { - - esp_log_level_set("*", ESP_LOG_NONE); - if (pod_settings_init() != ESP_OK) { ESP_LOGW(TAG, "settings NVS init failed; using defaults"); } @@ -196,6 +194,7 @@ void app_main(void) { cmd_battery_register(); cmd_ota_register(); cmd_ota_slave_progress_register(); + cmd_set_log_level_register(); } ESP_LOGI(TAG, "LED ring: UART LED_RING commands only (no local demo loop)"); diff --git a/main/proto/uart_messages.pb.c b/main/proto/uart_messages.pb.c index 25933c3..5e7ce06 100644 --- a/main/proto/uart_messages.pb.c +++ b/main/proto/uart_messages.pb.c @@ -111,6 +111,12 @@ PB_BIND(alox_RestartRequest, alox_RestartRequest, AUTO) PB_BIND(alox_RestartResponse, alox_RestartResponse, AUTO) +PB_BIND(alox_SetLogLevelRequest, alox_SetLogLevelRequest, AUTO) + + +PB_BIND(alox_SetLogLevelResponse, alox_SetLogLevelResponse, AUTO) + + PB_BIND(alox_OtaStartPayload, alox_OtaStartPayload, AUTO) diff --git a/main/proto/uart_messages.pb.h b/main/proto/uart_messages.pb.h index 9030807..a3fd503 100644 --- a/main/proto/uart_messages.pb.h +++ b/main/proto/uart_messages.pb.h @@ -34,7 +34,9 @@ typedef enum _alox_MessageType { /* * Combined cached accel + tap poll (one UART round-trip, ~16 ms cadence). */ alox_MessageType_CACHE_STATUS = 29, /* * Host → master → slave → master: timestamp echo round-trip (latency test). */ - alox_MessageType_ESPNOW_ECHO_PING = 30 + alox_MessageType_ESPNOW_ECHO_PING = 30, + /* * Host → master: get/set ESP-IDF log level for tag "*" (global). */ + alox_MessageType_SET_LOG_LEVEL = 31 } alox_MessageType; typedef enum _alox_TapKind { @@ -307,6 +309,18 @@ typedef struct _alox_RestartResponse { uint32_t client_id; } alox_RestartResponse; +/* * Host → master: read/write global log level (esp_log_level_set("*", …)). */ +typedef struct _alox_SetLogLevelRequest { + bool write; + /* * esp_log_level_t: 0=NONE, 1=ERROR, 2=WARN, 3=INFO, 4=DEBUG, 5=VERBOSE */ + uint32_t level; +} alox_SetLogLevelRequest; + +typedef struct _alox_SetLogLevelResponse { + bool success; + uint32_t level; +} alox_SetLogLevelResponse; + /* Host → device: begin UART OTA (erase inactive OTA slot; device replies OTA_STATUS). */ typedef struct _alox_OtaStartPayload { uint32_t total_size; @@ -391,6 +405,8 @@ typedef struct _alox_UartMessage { alox_CacheStatusResponse cache_status_response; alox_EspNowEchoPingRequest espnow_echo_ping_request; alox_EspNowEchoPingResponse espnow_echo_ping_response; + alox_SetLogLevelRequest set_log_level_request; + alox_SetLogLevelResponse set_log_level_response; } payload; } alox_UartMessage; @@ -401,8 +417,8 @@ extern "C" { /* Helper constants for enums */ #define _alox_MessageType_MIN alox_MessageType_UNKNOWN -#define _alox_MessageType_MAX alox_MessageType_ESPNOW_ECHO_PING -#define _alox_MessageType_ARRAYSIZE ((alox_MessageType)(alox_MessageType_ESPNOW_ECHO_PING+1)) +#define _alox_MessageType_MAX alox_MessageType_SET_LOG_LEVEL +#define _alox_MessageType_ARRAYSIZE ((alox_MessageType)(alox_MessageType_SET_LOG_LEVEL+1)) #define _alox_TapKind_MIN alox_TapKind_TAP_NONE #define _alox_TapKind_MAX alox_TapKind_TAP_TRIPLE @@ -451,6 +467,8 @@ extern "C" { + + @@ -490,6 +508,8 @@ extern "C" { #define alox_EspNowFindMeResponse_init_default {0, 0} #define alox_RestartRequest_init_default {0} #define alox_RestartResponse_init_default {0, 0} +#define alox_SetLogLevelRequest_init_default {0, 0} +#define alox_SetLogLevelResponse_init_default {0, 0} #define alox_OtaStartPayload_init_default {0} #define alox_OtaPayload_init_default {0, {0, {0}}} #define alox_OtaEndPayload_init_default {0} @@ -532,6 +552,8 @@ extern "C" { #define alox_EspNowFindMeResponse_init_zero {0, 0} #define alox_RestartRequest_init_zero {0} #define alox_RestartResponse_init_zero {0, 0} +#define alox_SetLogLevelRequest_init_zero {0, 0} +#define alox_SetLogLevelResponse_init_zero {0, 0} #define alox_OtaStartPayload_init_zero {0} #define alox_OtaPayload_init_zero {0, {0, {0}}} #define alox_OtaEndPayload_init_zero {0} @@ -655,6 +677,10 @@ extern "C" { #define alox_RestartRequest_client_id_tag 1 #define alox_RestartResponse_success_tag 1 #define alox_RestartResponse_client_id_tag 2 +#define alox_SetLogLevelRequest_write_tag 1 +#define alox_SetLogLevelRequest_level_tag 2 +#define alox_SetLogLevelResponse_success_tag 1 +#define alox_SetLogLevelResponse_level_tag 2 #define alox_OtaStartPayload_total_size_tag 1 #define alox_OtaPayload_seq_tag 1 #define alox_OtaPayload_data_tag 2 @@ -705,6 +731,8 @@ extern "C" { #define alox_UartMessage_cache_status_response_tag 34 #define alox_UartMessage_espnow_echo_ping_request_tag 35 #define alox_UartMessage_espnow_echo_ping_response_tag 36 +#define alox_UartMessage_set_log_level_request_tag 37 +#define alox_UartMessage_set_log_level_response_tag 38 /* Struct field encoding specification for nanopb */ #define alox_UartMessage_FIELDLIST(X, a) \ @@ -739,7 +767,9 @@ X(a, STATIC, ONEOF, MESSAGE, (payload,tap_notify_response,payload.tap_noti X(a, STATIC, ONEOF, MESSAGE, (payload,cache_status_request,payload.cache_status_request), 33) \ X(a, STATIC, ONEOF, MESSAGE, (payload,cache_status_response,payload.cache_status_response), 34) \ X(a, STATIC, ONEOF, MESSAGE, (payload,espnow_echo_ping_request,payload.espnow_echo_ping_request), 35) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,espnow_echo_ping_response,payload.espnow_echo_ping_response), 36) +X(a, STATIC, ONEOF, MESSAGE, (payload,espnow_echo_ping_response,payload.espnow_echo_ping_response), 36) \ +X(a, STATIC, ONEOF, MESSAGE, (payload,set_log_level_request,payload.set_log_level_request), 37) \ +X(a, STATIC, ONEOF, MESSAGE, (payload,set_log_level_response,payload.set_log_level_response), 38) #define alox_UartMessage_CALLBACK NULL #define alox_UartMessage_DEFAULT NULL #define alox_UartMessage_payload_ack_payload_MSGTYPE alox_Ack @@ -773,6 +803,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload,espnow_echo_ping_response,payload.es #define alox_UartMessage_payload_cache_status_response_MSGTYPE alox_CacheStatusResponse #define alox_UartMessage_payload_espnow_echo_ping_request_MSGTYPE alox_EspNowEchoPingRequest #define alox_UartMessage_payload_espnow_echo_ping_response_MSGTYPE alox_EspNowEchoPingResponse +#define alox_UartMessage_payload_set_log_level_request_MSGTYPE alox_SetLogLevelRequest +#define alox_UartMessage_payload_set_log_level_response_MSGTYPE alox_SetLogLevelResponse #define alox_Ack_FIELDLIST(X, a) \ @@ -1034,6 +1066,18 @@ X(a, STATIC, SINGULAR, UINT32, client_id, 2) #define alox_RestartResponse_CALLBACK NULL #define alox_RestartResponse_DEFAULT NULL +#define alox_SetLogLevelRequest_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, BOOL, write, 1) \ +X(a, STATIC, SINGULAR, UINT32, level, 2) +#define alox_SetLogLevelRequest_CALLBACK NULL +#define alox_SetLogLevelRequest_DEFAULT NULL + +#define alox_SetLogLevelResponse_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, BOOL, success, 1) \ +X(a, STATIC, SINGULAR, UINT32, level, 2) +#define alox_SetLogLevelResponse_CALLBACK NULL +#define alox_SetLogLevelResponse_DEFAULT NULL + #define alox_OtaStartPayload_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UINT32, total_size, 1) #define alox_OtaStartPayload_CALLBACK NULL @@ -1117,6 +1161,8 @@ extern const pb_msgdesc_t alox_EspNowFindMeRequest_msg; extern const pb_msgdesc_t alox_EspNowFindMeResponse_msg; extern const pb_msgdesc_t alox_RestartRequest_msg; extern const pb_msgdesc_t alox_RestartResponse_msg; +extern const pb_msgdesc_t alox_SetLogLevelRequest_msg; +extern const pb_msgdesc_t alox_SetLogLevelResponse_msg; extern const pb_msgdesc_t alox_OtaStartPayload_msg; extern const pb_msgdesc_t alox_OtaPayload_msg; extern const pb_msgdesc_t alox_OtaEndPayload_msg; @@ -1161,6 +1207,8 @@ extern const pb_msgdesc_t alox_OtaSlaveProgressResponse_msg; #define alox_EspNowFindMeResponse_fields &alox_EspNowFindMeResponse_msg #define alox_RestartRequest_fields &alox_RestartRequest_msg #define alox_RestartResponse_fields &alox_RestartResponse_msg +#define alox_SetLogLevelRequest_fields &alox_SetLogLevelRequest_msg +#define alox_SetLogLevelResponse_fields &alox_SetLogLevelResponse_msg #define alox_OtaStartPayload_fields &alox_OtaStartPayload_msg #define alox_OtaPayload_fields &alox_OtaPayload_msg #define alox_OtaEndPayload_fields &alox_OtaEndPayload_msg @@ -1210,6 +1258,8 @@ extern const pb_msgdesc_t alox_OtaSlaveProgressResponse_msg; #define alox_OtaStatusPayload_size 24 #define alox_RestartRequest_size 6 #define alox_RestartResponse_size 8 +#define alox_SetLogLevelRequest_size 8 +#define alox_SetLogLevelResponse_size 8 #define alox_TapEvent_size 16 #define alox_TapNotifyRequest_size 16 #define alox_TapNotifyResponse_size 20 diff --git a/main/proto/uart_messages.proto b/main/proto/uart_messages.proto index 4f71433..8be83a5 100644 --- a/main/proto/uart_messages.proto +++ b/main/proto/uart_messages.proto @@ -31,6 +31,8 @@ enum MessageType { CACHE_STATUS = 29; /** Host → master → slave → master: timestamp echo round-trip (latency test). */ ESPNOW_ECHO_PING = 30; + /** Host → master: get/set ESP-IDF log level for tag "*" (global). */ + SET_LOG_LEVEL = 31; } message UartMessage { @@ -67,6 +69,8 @@ message UartMessage { CacheStatusResponse cache_status_response = 34; EspNowEchoPingRequest espnow_echo_ping_request = 35; EspNowEchoPingResponse espnow_echo_ping_response = 36; + SetLogLevelRequest set_log_level_request = 37; + SetLogLevelResponse set_log_level_response = 38; } } @@ -329,6 +333,18 @@ message RestartResponse { uint32 client_id = 2; } +/** Host → master: read/write global log level (esp_log_level_set("*", …)). */ +message SetLogLevelRequest { + bool write = 1; + /** esp_log_level_t: 0=NONE, 1=ERROR, 2=WARN, 3=INFO, 4=DEBUG, 5=VERBOSE */ + uint32 level = 2; +} + +message SetLogLevelResponse { + bool success = 1; + uint32 level = 2; +} + // Host → device: begin UART OTA (erase inactive OTA slot; device replies OTA_STATUS). message OtaStartPayload { uint32 total_size = 1;