diff --git a/docs/DOCUMENTATION.md b/docs/DOCUMENTATION.md index ed38b76..21798fa 100644 --- a/docs/DOCUMENTATION.md +++ b/docs/DOCUMENTATION.md @@ -175,6 +175,7 @@ UART_CMD_REQ(&uart_msg, alox_UartMessage_accel_deadzone_request_tag, accel_deadz | `ESPNOW_SLAVE_INFO` | S→M | `slave_info` | Erste Registrierung | | `ESPNOW_HEARTBEAT` | S→M | `heartbeat` | Keepalive 1 s | | `ESPNOW_SET_ACCEL_DEADZONE` | M→S | `accel_deadzone` | Deadzone LSB | +| `ESPNOW_SET_TAP_CONFIG` | M→S | `tap_config` | Multitap-Parameter + NVS | | `ESPNOW_SET_ACCEL_STREAM` | M→S | `accel_stream` | Stream ~16 ms | | `ESPNOW_ACCEL_SAMPLE` | S→M | `accel_sample` | x/y/z Roh-LSB | | `ESPNOW_SET_TAP_NOTIFY` | M→S | `tap_notify` | Tap-Arten filtern | @@ -238,6 +239,7 @@ Nur auf dem **Master** registriert (`powerpod.c`). IDs aus `MessageType` in `uar | 29 | CACHE_STATUS | `cmd_cache_status.c` | Accel + Tap Cache (ein Round-Trip) | | 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 | +| 32 | TAP_CONFIG | `cmd_tap_config.c` | BMA456 Multitap-Parameter + NVS | ### 7.1 VERSION (3) @@ -264,6 +266,12 @@ Nur auf dem **Master** registriert (`powerpod.c`). IDs aus `MessageType` in `uar - Konfiguriert auf Slave welche Tap-Arten `ESPNOW_TAP_EVENT` auslösen. - Tap-Quelle: BMA456-Interrupt → `on_bma456_tap` in `esp_now_comm.c`. +### 7.5a TAP_CONFIG (32) + +- **Request:** `write`, `client_id` (0=lokal), `all_clients`, Multitap-Felder (`tap_sens_thres` … `enable_triple`). +- **Write:** `bma456_set_tap_config` + NVS `tap_cfg` lokal; Slaves via `ESPNOW_SET_TAP_CONFIG`. +- Boot: `pod_settings_apply_tap_config()` nach `init_bma456()`. + ### 7.6 CACHE_STATUS (29) - **Request:** leer. @@ -437,6 +445,7 @@ Aktivierbar mit `POWERPOD_BATTERY_UV_ENABLE` in `powerpod.h` (CMake-Override mö | Key | Inhalt | |-----|--------| | `accel_dz` | Accel-Deadzone LSB | +| `tap_cfg` | BMA456 Multitap-Config (Blob) | | `uv_latch` | Software-UV-Zustand (`1` = Energiesparmodus) | Gespeichert bei lokalem Set (UART `client_id=0`, ESP-NOW auf Slave). Geladen nach `init_bma456()`. @@ -492,6 +501,7 @@ Includes in generierten `.pb.c` müssen `"uart_messages.pb.h"` heißen (nicht `m | `cmd_client_info.c` | CLIENT_INFO | | `cmd_accel_deadzone.c` | ACCEL_DEADZONE | | `cmd_accel_stream.c` | ACCEL_STREAM | +| `cmd_tap_config.c` | TAP_CONFIG | | `cmd_tap_notify.c` | TAP_NOTIFY | | `cmd_cache_status.c` | CACHE_STATUS | | `cmd_battery.c` | BATTERY_STATUS | diff --git a/goTool/README.md b/goTool/README.md index 44ad0cb..01eda4f 100644 --- a/goTool/README.md +++ b/goTool/README.md @@ -25,6 +25,7 @@ go run . -port /dev/ttyUSB0 clients | `version` | `0x03` | Prints `version` and `git_hash` from firmware | | `clients` | `0x04` | Lists slaves registered on the master via ESP-NOW | | `deadzone` | `0x06` | Get/set accelerometer deadzone LSB (`-set`, `-value`, `-client`, `-all`) | +| `tap-config` | `0x20` | Get/set BMA456 tap detection params (`-set`, `-client`, `-all`, `-sens`, `-max-gest`, `-shock`, `-quiet`, `-wait`, `-axis`, `-single`, `-double`, `-triple`) | | `tap-notify` | `0x1b` | Get/set which tap kinds (single/double/triple) notify via ESP-NOW (`-set`, `-client`, `-all`, `-single`, `-double`, `-triple`) | | `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`) | @@ -94,6 +95,8 @@ If the UART device is unplugged or the port disappears, `serve` keeps running an CLI: ```bash +go run . -port /dev/ttyUSB0 tap-config +go run . -port /dev/ttyUSB0 tap-config -set -sens 5 -axis 2 go run . -port /dev/ttyUSB0 tap-notify -client 16 -set -single go run . -port /dev/ttyUSB0 cache-status ``` diff --git a/goTool/api_serve.go b/goTool/api_serve.go index 9f81c2b..6106024 100644 --- a/goTool/api_serve.go +++ b/goTool/api_serve.go @@ -86,16 +86,17 @@ type logLevelAPIRequest struct { } type otaAPIResponse struct { - Success bool `json:"success"` - BytesWritten uint32 `json:"bytes_written,omitempty"` - TargetSlot uint32 `json:"target_slot,omitempty"` - Error string `json:"error,omitempty"` + Success bool `json:"success"` + BytesWritten uint32 `json:"bytes_written,omitempty"` + TargetSlot uint32 `json:"target_slot,omitempty"` + Error string `json:"error,omitempty"` } func mountServeAPI(mux *http.ServeMux, link *managedSerial, hub *wsHub, streamCtl *accelStreamCtl, tapCtl *tapNotifyCtl) { mountLiveStreamAPI(mux, hub) mountAccelStreamAPI(mux, link, hub, streamCtl) mountTapAPI(mux, link, hub, tapCtl) + mountTapConfigAPI(mux, link) mountLedRingAPI(mux, link) mountBatteryAPI(mux, link) mux.HandleFunc("/api/deadzone", func(w http.ResponseWriter, r *http.Request) { diff --git a/goTool/api_tap_config.go b/goTool/api_tap_config.go new file mode 100644 index 0000000..48ef443 --- /dev/null +++ b/goTool/api_tap_config.go @@ -0,0 +1,171 @@ +package main + +import ( + "encoding/json" + "fmt" + "net/http" + + "powerpod/gotool/pb" +) + +type tapConfigFields struct { + TapSensThres uint32 `json:"tap_sens_thres"` + MaxGestDur uint32 `json:"max_gest_dur"` + TapShockDur uint32 `json:"tap_shock_dur"` + QuiteTimeAfterGest uint32 `json:"quite_time_after_gest"` + WaitForTimeout uint32 `json:"wait_for_timeout"` + AxisSel uint32 `json:"axis_sel"` + EnableSingle bool `json:"enable_single"` + EnableDouble bool `json:"enable_double"` + EnableTriple bool `json:"enable_triple"` +} + +type tapConfigAPIResponse struct { + tapConfigFields + ClientID uint32 `json:"client_id"` + Success bool `json:"success"` + SlavesUpdated uint32 `json:"slaves_updated"` + Error string `json:"error,omitempty"` +} + +type tapConfigAPIRequest struct { + Write bool `json:"write"` + ClientID uint32 `json:"client_id"` + AllClients bool `json:"all_clients"` + // SlavesOnly: with all_clients, push to ESP-NOW slaves only (master BMA456 unchanged). + SlavesOnly bool `json:"slaves_only"` + tapConfigFields +} + +func tapConfigFieldsFromPB(r *pb.TapConfigResponse) tapConfigFields { + return tapConfigFields{ + TapSensThres: r.GetTapSensThres(), + MaxGestDur: r.GetMaxGestDur(), + TapShockDur: r.GetTapShockDur(), + QuiteTimeAfterGest: r.GetQuiteTimeAfterGest(), + WaitForTimeout: r.GetWaitForTimeout(), + AxisSel: r.GetAxisSel(), + EnableSingle: r.GetEnableSingle(), + EnableDouble: r.GetEnableDouble(), + EnableTriple: r.GetEnableTriple(), + } +} + +func (f tapConfigFields) toPBRequest(write bool, clientID uint32, all bool) *pb.TapConfigRequest { + return &pb.TapConfigRequest{ + Write: write, + ClientId: clientID, + AllClients: all, + TapSensThres: f.TapSensThres, + MaxGestDur: f.MaxGestDur, + TapShockDur: f.TapShockDur, + QuiteTimeAfterGest: f.QuiteTimeAfterGest, + WaitForTimeout: f.WaitForTimeout, + AxisSel: f.AxisSel, + EnableSingle: f.EnableSingle, + EnableDouble: f.EnableDouble, + EnableTriple: f.EnableTriple, + } +} + +func mountTapConfigAPI(mux *http.ServeMux, link *managedSerial) { + mux.HandleFunc("/api/tap-config", func(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case http.MethodGet: + serveTapConfigGet(w, r, link) + case http.MethodPost: + serveTapConfigPost(w, r, link) + default: + http.Error(w, "method not allowed", http.StatusMethodNotAllowed) + } + }) +} + +func serveTapConfigGet(w http.ResponseWriter, r *http.Request, link *managedSerial) { + clientID, err := parseUintQuery(r, "client_id", 0) + if err != nil { + writeJSON(w, http.StatusBadRequest, tapConfigAPIResponse{Error: err.Error()}) + return + } + resp, err := link.TapConfig(&pb.TapConfigRequest{ + Write: false, + ClientId: clientID, + }) + if err != nil { + writeJSON(w, http.StatusServiceUnavailable, tapConfigAPIResponse{ + ClientID: clientID, + Error: err.Error(), + }) + return + } + out := tapConfigAPIResponse{ + tapConfigFields: tapConfigFieldsFromPB(resp), + ClientID: resp.GetClientId(), + Success: resp.GetSuccess(), + } + writeJSON(w, http.StatusOK, out) +} + +func serveTapConfigPost(w http.ResponseWriter, r *http.Request, link *managedSerial) { + var body tapConfigAPIRequest + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + writeJSON(w, http.StatusBadRequest, tapConfigAPIResponse{Error: "invalid JSON"}) + return + } + if body.AllClients && body.SlavesOnly { + updated, err := applyTapConfigToSlaves(link, body.tapConfigFields) + if err != nil { + writeJSON(w, http.StatusServiceUnavailable, tapConfigAPIResponse{ + tapConfigFields: body.tapConfigFields, + Error: err.Error(), + }) + return + } + writeJSON(w, http.StatusOK, tapConfigAPIResponse{ + tapConfigFields: body.tapConfigFields, + Success: updated > 0, + SlavesUpdated: updated, + }) + return + } + + resp, err := link.TapConfig(body.tapConfigFields.toPBRequest(true, body.ClientID, body.AllClients)) + if err != nil { + writeJSON(w, http.StatusServiceUnavailable, tapConfigAPIResponse{ + ClientID: body.ClientID, + tapConfigFields: body.tapConfigFields, + Error: err.Error(), + }) + return + } + writeJSON(w, http.StatusOK, tapConfigAPIResponse{ + tapConfigFields: tapConfigFieldsFromPB(resp), + ClientID: resp.GetClientId(), + Success: resp.GetSuccess(), + SlavesUpdated: resp.GetSlavesUpdated(), + }) +} + +func applyTapConfigToSlaves(link *managedSerial, fields tapConfigFields) (uint32, error) { + clients, err := link.listClients() + if err != nil { + return 0, err + } + var updated uint32 + for _, c := range clients { + resp, err := link.TapConfig(fields.toPBRequest(true, c.GetId(), false)) + if err != nil { + continue + } + if resp.GetSuccess() { + updated++ + } + } + if len(clients) == 0 { + return 0, fmt.Errorf("no slaves registered") + } + if updated == 0 { + return 0, fmt.Errorf("tap config not applied to any slave") + } + return updated, nil +} diff --git a/goTool/client_api.go b/goTool/client_api.go index 4fefd36..4f22b4c 100644 --- a/goTool/client_api.go +++ b/goTool/client_api.go @@ -225,6 +225,27 @@ func (m *managedSerial) AccelDeadzonePoll(req *pb.AccelDeadzoneRequest) (*pb.Acc return m.accelDeadzoneVia(m.withPortPoll, req) } +func (m *managedSerial) TapConfig(req *pb.TapConfigRequest) (*pb.TapConfigResponse, error) { + return m.tapConfigVia(m.withPort, req) +} + +func (m *managedSerial) TapConfigPoll(req *pb.TapConfigRequest) (*pb.TapConfigResponse, error) { + return m.tapConfigVia(m.withPortPoll, req) +} + +func (m *managedSerial) tapConfigVia( + portFn func(func(*serialPort) error) error, + req *pb.TapConfigRequest, +) (*pb.TapConfigResponse, error) { + var resp *pb.TapConfigResponse + err := portFn(func(sp *serialPort) error { + var e error + resp, e = sp.TapConfig(req) + return e + }) + return resp, err +} + func (m *managedSerial) accelDeadzoneVia( portFn func(func(*serialPort) error) error, req *pb.AccelDeadzoneRequest, @@ -383,6 +404,33 @@ func (s *serialPort) accelDeadzone(req *pb.AccelDeadzoneRequest) (*pb.AccelDeadz return r, nil } +func (s *serialPort) tapConfig(req *pb.TapConfigRequest) (*pb.TapConfigResponse, error) { + msg := &pb.UartMessage{ + Type: pb.MessageType_TAP_CONFIG, + Payload: &pb.UartMessage_TapConfigRequest{ + TapConfigRequest: req, + }, + } + body, err := proto.Marshal(msg) + if err != nil { + return nil, fmt.Errorf("encode: %w", err) + } + payload := append([]byte{byte(pb.MessageType_TAP_CONFIG)}, body...) + respPayload, err := s.exchangePayload(payload, "TAP_CONFIG") + if err != nil { + return nil, err + } + var respMsg pb.UartMessage + if err := proto.Unmarshal(respPayload[1:], &respMsg); err != nil { + return nil, fmt.Errorf("decode: %w", err) + } + r := respMsg.GetTapConfigResponse() + if r == nil { + return nil, fmt.Errorf("missing tap_config_response") + } + return r, nil +} + func (s *serialPort) espnowUnicastTest(clientID, seq uint32) (*pb.EspNowUnicastTestResponse, error) { req := &pb.EspNowUnicastTestRequest{ClientId: clientID, Seq: seq} msg := &pb.UartMessage{ @@ -557,6 +605,10 @@ func (s *serialPort) AccelDeadzone(req *pb.AccelDeadzoneRequest) (*pb.AccelDeadz return s.accelDeadzone(req) } +func (s *serialPort) TapConfig(req *pb.TapConfigRequest) (*pb.TapConfigResponse, error) { + return s.tapConfig(req) +} + func (s *serialPort) EspnowUnicastTest(clientID, seq uint32) (*pb.EspNowUnicastTestResponse, error) { return s.espnowUnicastTest(clientID, seq) } diff --git a/goTool/cmd_tap_config.go b/goTool/cmd_tap_config.go new file mode 100644 index 0000000..762c672 --- /dev/null +++ b/goTool/cmd_tap_config.go @@ -0,0 +1,54 @@ +package main + +import ( + "flag" + "fmt" + + "powerpod/gotool/pb" +) + +func runTapConfig(sp *serialPort, args []string) error { + fs := flag.NewFlagSet("tap-config", flag.ExitOnError) + write := fs.Bool("set", false, "write tap config (default: read)") + clientID := fs.Uint("client", 0, "client id (0=local master BMA456)") + all := fs.Bool("all", false, "apply to all registered slaves (master only)") + sens := fs.Uint("sens", 5, "tap_sens_thres 0=most … 15=least") + maxGest := fs.Uint("max-gest", 100, "max_gest_dur (×5 ms)") + shock := fs.Uint("shock", 6, "tap_shock_dur (×5 ms)") + quiet := fs.Uint("quiet", 60, "quite_time_after_gest (×5 ms)") + wait := fs.Uint("wait", 0, "wait_for_timeout 0|1") + axis := fs.Uint("axis", 2, "axis_sel 0=X 1=Y 2=Z") + single := fs.Bool("single", true, "enable single tap") + doubleTap := fs.Bool("double", true, "enable double tap") + triple := fs.Bool("triple", true, "enable triple tap") + if err := fs.Parse(args); err != nil { + return err + } + + r, err := sp.tapConfig(&pb.TapConfigRequest{ + Write: *write, + ClientId: uint32(*clientID), + AllClients: *all, + TapSensThres: uint32(*sens), + MaxGestDur: uint32(*maxGest), + TapShockDur: uint32(*shock), + QuiteTimeAfterGest: uint32(*quiet), + WaitForTimeout: uint32(*wait), + AxisSel: uint32(*axis), + EnableSingle: *single, + EnableDouble: *doubleTap, + EnableTriple: *triple, + }) + if err != nil { + return err + } + + fmt.Printf("client_id=%d success=%v slaves_updated=%d\n", + r.GetClientId(), r.GetSuccess(), r.GetSlavesUpdated()) + fmt.Printf(" sens=%d max_gest=%d shock=%d quiet=%d wait=%d axis=%d\n", + r.GetTapSensThres(), r.GetMaxGestDur(), r.GetTapShockDur(), + r.GetQuiteTimeAfterGest(), r.GetWaitForTimeout(), r.GetAxisSel()) + fmt.Printf(" enable single=%v double=%v triple=%v\n", + r.GetEnableSingle(), r.GetEnableDouble(), r.GetEnableTriple()) + return nil +} diff --git a/goTool/dashboard.go b/goTool/dashboard.go index 761d05e..0642545 100644 --- a/goTool/dashboard.go +++ b/goTool/dashboard.go @@ -15,31 +15,45 @@ import ( ) type MasterView struct { - Version uint32 `json:"version"` - GitHash string `json:"git_hash"` - RunningPartition string `json:"running_partition,omitempty"` - Deadzone uint32 `json:"deadzone,omitempty"` - Lipo1 lipoReadingJSON `json:"lipo1"` - Lipo2 lipoReadingJSON `json:"lipo2"` - BatteryAgeMs uint32 `json:"battery_age_ms,omitempty"` - OK bool `json:"ok"` - Error string `json:"error,omitempty"` + Version uint32 `json:"version"` + GitHash string `json:"git_hash"` + RunningPartition string `json:"running_partition,omitempty"` + Deadzone uint32 `json:"deadzone,omitempty"` + TapConfig *TapConfigView `json:"tap_config,omitempty"` + Lipo1 lipoReadingJSON `json:"lipo1"` + Lipo2 lipoReadingJSON `json:"lipo2"` + BatteryAgeMs uint32 `json:"battery_age_ms,omitempty"` + OK bool `json:"ok"` + Error string `json:"error,omitempty"` +} + +type TapConfigView struct { + TapSensThres uint32 `json:"tap_sens_thres"` + MaxGestDur uint32 `json:"max_gest_dur"` + TapShockDur uint32 `json:"tap_shock_dur"` + QuiteTimeAfterGest uint32 `json:"quite_time_after_gest"` + WaitForTimeout uint32 `json:"wait_for_timeout"` + AxisSel uint32 `json:"axis_sel"` + EnableSingle bool `json:"enable_single"` + EnableDouble bool `json:"enable_double"` + EnableTriple bool `json:"enable_triple"` } type ClientView struct { - ID uint32 `json:"id"` - MAC string `json:"mac"` - Version uint32 `json:"version"` - Deadzone uint32 `json:"deadzone,omitempty"` - Available bool `json:"available"` - Used bool `json:"used"` - LastPing uint32 `json:"last_ping"` - LastSuccessPing uint32 `json:"last_success_ping"` - AccelValid bool `json:"accel_valid"` - AccelX int32 `json:"accel_x"` - AccelY int32 `json:"accel_y"` - AccelZ int32 `json:"accel_z"` - AccelAgeMs uint32 `json:"accel_age_ms"` + ID uint32 `json:"id"` + MAC string `json:"mac"` + Version uint32 `json:"version"` + Deadzone uint32 `json:"deadzone,omitempty"` + TapConfig *TapConfigView `json:"tap_config,omitempty"` + Available bool `json:"available"` + Used bool `json:"used"` + LastPing uint32 `json:"last_ping"` + LastSuccessPing uint32 `json:"last_success_ping"` + AccelValid bool `json:"accel_valid"` + AccelX int32 `json:"accel_x"` + AccelY int32 `json:"accel_y"` + AccelZ int32 `json:"accel_z"` + AccelAgeMs uint32 `json:"accel_age_ms"` AccelStream bool `json:"accel_stream"` TapNotifySingle bool `json:"tap_notify_single"` TapNotifyDouble bool `json:"tap_notify_double"` @@ -52,15 +66,15 @@ type ClientView struct { } type DashboardState struct { - UpdatedAt string `json:"updated_at"` - SerialPort string `json:"serial_port"` - UARTConnected bool `json:"uart_connected"` - SerialOK bool `json:"serial_ok"` - SerialError string `json:"serial_error,omitempty"` + UpdatedAt string `json:"updated_at"` + SerialPort string `json:"serial_port"` + UARTConnected bool `json:"uart_connected"` + SerialOK bool `json:"serial_ok"` + SerialError string `json:"serial_error,omitempty"` /** Host: fast CACHE_STATUS poll (~16 ms) for accel + tap. */ - LiveStream bool `json:"live_stream"` - Master MasterView `json:"master"` - Clients []ClientView `json:"clients"` + LiveStream bool `json:"live_stream"` + Master MasterView `json:"master"` + Clients []ClientView `json:"clients"` } type wsHub struct { @@ -540,6 +554,9 @@ func pollDashboard(link *managedSerial, portName string, last *DashboardState, s if dz, err := readDeadzonePoll(link, 0); err == nil { st.Master.Deadzone = dz } + if tc, err := readTapConfigPoll(link, 0); err == nil { + st.Master.TapConfig = tc + } clients, err := link.listClientsPoll() if err != nil { @@ -574,6 +591,9 @@ func pollDashboard(link *managedSerial, portName string, last *DashboardState, s if dz, err := readDeadzonePoll(link, c.GetId()); err == nil { st.Clients[i].Deadzone = dz } + if tc, err := readTapConfigPoll(link, c.GetId()); err == nil { + st.Clients[i].TapConfig = tc + } } } if last != nil { @@ -714,6 +734,34 @@ func readDeadzonePoll(link *managedSerial, clientID uint32) (uint32, error) { return r.GetDeadzone(), nil } +func tapConfigViewFromPB(r *pb.TapConfigResponse) *TapConfigView { + return &TapConfigView{ + TapSensThres: r.GetTapSensThres(), + MaxGestDur: r.GetMaxGestDur(), + TapShockDur: r.GetTapShockDur(), + QuiteTimeAfterGest: r.GetQuiteTimeAfterGest(), + WaitForTimeout: r.GetWaitForTimeout(), + AxisSel: r.GetAxisSel(), + EnableSingle: r.GetEnableSingle(), + EnableDouble: r.GetEnableDouble(), + EnableTriple: r.GetEnableTriple(), + } +} + +func readTapConfigPoll(link *managedSerial, clientID uint32) (*TapConfigView, error) { + r, err := link.TapConfigPoll(&pb.TapConfigRequest{ + Write: false, + ClientId: clientID, + }) + if err != nil { + return nil, err + } + if !r.GetSuccess() { + return nil, fmt.Errorf("tap config read failed for client %d", clientID) + } + return tapConfigViewFromPB(r), nil +} + func formatMAC(mac []byte) string { if len(mac) == 0 { return "" diff --git a/goTool/docs/API_REST.md b/goTool/docs/API_REST.md index bf1bfb1..1a0c08c 100644 --- a/goTool/docs/API_REST.md +++ b/goTool/docs/API_REST.md @@ -209,6 +209,46 @@ With `all_clients` + `slaves_only`: push to ESP-NOW slaves only (master BMA456 u {"deadzone": 128, "client_id": 0, "success": true, "slaves_updated": 2} ``` +### Tap config (BMA456 multitap) + +```http +GET /api/tap-config?client_id=0 +POST /api/tap-config +Content-Type: application/json +{ + "write": true, + "client_id": 0, + "tap_sens_thres": 5, + "max_gest_dur": 100, + "tap_shock_dur": 6, + "quite_time_after_gest": 60, + "wait_for_timeout": 0, + "axis_sel": 2, + "enable_single": true, + "enable_double": true, + "enable_triple": true +} +``` + +Same `client_id` / `all_clients` / `slaves_only` semantics as deadzone. Values are applied to the sensor and persisted in NVS on each target node. + +```json +{ + "client_id": 0, + "success": true, + "slaves_updated": 0, + "tap_sens_thres": 5, + "max_gest_dur": 100, + "tap_shock_dur": 6, + "quite_time_after_gest": 60, + "wait_for_timeout": 0, + "axis_sel": 2, + "enable_single": true, + "enable_double": true, + "enable_triple": true +} +``` + ### Unicast test ```http @@ -361,6 +401,8 @@ Same as external API: | Nur Master deadzone | `POST /api/deadzone` `client_id: 0` or CLI `deadzone -set -client 0` | | Einzelner Slave | `client_id: ` | | Alle Slaves deadzone | `all_clients` + `slaves_only` on POST | +| Master tap config | `GET` / `POST /api/tap-config` `client_id: 0` or CLI `tap-config` | +| Tap-Cfg alle Slaves | `POST /api/tap-config` with `all_clients` + `slaves_only` | | Unicast test | `POST /api/unicast-test` | | 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` | diff --git a/goTool/main.go b/goTool/main.go index b468c46..8613863 100644 --- a/goTool/main.go +++ b/goTool/main.go @@ -16,6 +16,7 @@ func usage() { fmt.Fprintf(os.Stderr, " version firmware version and git hash\n") fmt.Fprintf(os.Stderr, " clients registered ESP-NOW slaves on the master\n") fmt.Fprintf(os.Stderr, " deadzone get/set accelerometer deadzone (LSB)\n") + fmt.Fprintf(os.Stderr, " tap-config get/set BMA456 tap detection parameters\n") fmt.Fprintf(os.Stderr, " tap-notify get/set which tap kinds notify via ESP-NOW\n") fmt.Fprintf(os.Stderr, " 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") @@ -54,7 +55,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", "log-level", "log_level", "ota", "ota-progress", "ota_progress": + case "version", "clients", "client-info", "deadzone", "accel-deadzone", "tap-config", "tap_config", "tap-notify", "tap_notify", "cache-status", "cache_status", "unicast-test", "unicast_test", "echo-ping", "echo_ping", "led-ring", "led_ring", "find-me", "find_me", "restart", "log-level", "log_level", "ota", "ota-progress", "ota_progress": if *portName == "" { fmt.Fprintf(os.Stderr, "command %q requires -port\n\n", cmd) usage() @@ -74,6 +75,8 @@ func main() { runErr = runClients(sp) case "deadzone", "accel-deadzone": runErr = runDeadzone(sp, flag.Args()[1:]) + case "tap-config", "tap_config": + runErr = runTapConfig(sp, flag.Args()[1:]) case "tap-notify", "tap_notify": runErr = runTapNotify(sp, flag.Args()[1:]) case "cache-status", "cache_status": diff --git a/goTool/pb/uart_messages.pb.go b/goTool/pb/uart_messages.pb.go index 87f2063..08cd7b4 100644 --- a/goTool/pb/uart_messages.pb.go +++ b/goTool/pb/uart_messages.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.11 -// protoc v7.34.1 +// protoc v7.36.0 // source: uart_messages.proto package pb @@ -50,6 +50,8 @@ const ( MessageType_ESPNOW_ECHO_PING MessageType = 30 // * Host → master: get/set ESP-IDF log level for tag "*" (global). MessageType_SET_LOG_LEVEL MessageType = 31 + // * Host → master: get/set BMA456H multitap detection parameters. + MessageType_TAP_CONFIG MessageType = 32 ) // Enum value maps for MessageType. @@ -78,6 +80,7 @@ var ( 29: "CACHE_STATUS", 30: "ESPNOW_ECHO_PING", 31: "SET_LOG_LEVEL", + 32: "TAP_CONFIG", } MessageType_value = map[string]int32{ "UNKNOWN": 0, @@ -103,6 +106,7 @@ var ( "CACHE_STATUS": 29, "ESPNOW_ECHO_PING": 30, "SET_LOG_LEVEL": 31, + "TAP_CONFIG": 32, } ) @@ -223,6 +227,8 @@ type UartMessage struct { // *UartMessage_EspnowEchoPingResponse // *UartMessage_SetLogLevelRequest // *UartMessage_SetLogLevelResponse + // *UartMessage_TapConfigRequest + // *UartMessage_TapConfigResponse Payload isUartMessage_Payload `protobuf_oneof:"payload"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -569,6 +575,24 @@ func (x *UartMessage) GetSetLogLevelResponse() *SetLogLevelResponse { return nil } +func (x *UartMessage) GetTapConfigRequest() *TapConfigRequest { + if x != nil { + if x, ok := x.Payload.(*UartMessage_TapConfigRequest); ok { + return x.TapConfigRequest + } + } + return nil +} + +func (x *UartMessage) GetTapConfigResponse() *TapConfigResponse { + if x != nil { + if x, ok := x.Payload.(*UartMessage_TapConfigResponse); ok { + return x.TapConfigResponse + } + } + return nil +} + type isUartMessage_Payload interface { isUartMessage_Payload() } @@ -705,6 +729,14 @@ type UartMessage_SetLogLevelResponse struct { SetLogLevelResponse *SetLogLevelResponse `protobuf:"bytes,38,opt,name=set_log_level_response,json=setLogLevelResponse,proto3,oneof"` } +type UartMessage_TapConfigRequest struct { + TapConfigRequest *TapConfigRequest `protobuf:"bytes,39,opt,name=tap_config_request,json=tapConfigRequest,proto3,oneof"` +} + +type UartMessage_TapConfigResponse struct { + TapConfigResponse *TapConfigResponse `protobuf:"bytes,40,opt,name=tap_config_response,json=tapConfigResponse,proto3,oneof"` +} + func (*UartMessage_AckPayload) isUartMessage_Payload() {} func (*UartMessage_EchoPayload) isUartMessage_Payload() {} @@ -771,6 +803,10 @@ func (*UartMessage_SetLogLevelRequest) isUartMessage_Payload() {} func (*UartMessage_SetLogLevelResponse) isUartMessage_Payload() {} +func (*UartMessage_TapConfigRequest) isUartMessage_Payload() {} + +func (*UartMessage_TapConfigResponse) isUartMessage_Payload() {} + type Ack struct { state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields @@ -3051,6 +3087,272 @@ func (x *SetLogLevelResponse) GetLevel() uint32 { return 0 } +// write=false: read tap config; write=true: apply + persist on target node. +// client_id 0 = local BMA456; >0 = slave id on master; all_clients = push to all slaves. +type TapConfigRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Write bool `protobuf:"varint,1,opt,name=write,proto3" json:"write,omitempty"` + ClientId uint32 `protobuf:"varint,2,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` + AllClients bool `protobuf:"varint,3,opt,name=all_clients,json=allClients,proto3" json:"all_clients,omitempty"` + TapSensThres uint32 `protobuf:"varint,4,opt,name=tap_sens_thres,json=tapSensThres,proto3" json:"tap_sens_thres,omitempty"` + MaxGestDur uint32 `protobuf:"varint,5,opt,name=max_gest_dur,json=maxGestDur,proto3" json:"max_gest_dur,omitempty"` + TapShockDur uint32 `protobuf:"varint,6,opt,name=tap_shock_dur,json=tapShockDur,proto3" json:"tap_shock_dur,omitempty"` + QuiteTimeAfterGest uint32 `protobuf:"varint,7,opt,name=quite_time_after_gest,json=quiteTimeAfterGest,proto3" json:"quite_time_after_gest,omitempty"` + WaitForTimeout uint32 `protobuf:"varint,8,opt,name=wait_for_timeout,json=waitForTimeout,proto3" json:"wait_for_timeout,omitempty"` + AxisSel uint32 `protobuf:"varint,9,opt,name=axis_sel,json=axisSel,proto3" json:"axis_sel,omitempty"` + EnableSingle bool `protobuf:"varint,10,opt,name=enable_single,json=enableSingle,proto3" json:"enable_single,omitempty"` + EnableDouble bool `protobuf:"varint,11,opt,name=enable_double,json=enableDouble,proto3" json:"enable_double,omitempty"` + EnableTriple bool `protobuf:"varint,12,opt,name=enable_triple,json=enableTriple,proto3" json:"enable_triple,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TapConfigRequest) Reset() { + *x = TapConfigRequest{} + mi := &file_uart_messages_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TapConfigRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TapConfigRequest) ProtoMessage() {} + +func (x *TapConfigRequest) ProtoReflect() protoreflect.Message { + mi := &file_uart_messages_proto_msgTypes[37] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TapConfigRequest.ProtoReflect.Descriptor instead. +func (*TapConfigRequest) Descriptor() ([]byte, []int) { + return file_uart_messages_proto_rawDescGZIP(), []int{37} +} + +func (x *TapConfigRequest) GetWrite() bool { + if x != nil { + return x.Write + } + return false +} + +func (x *TapConfigRequest) GetClientId() uint32 { + if x != nil { + return x.ClientId + } + return 0 +} + +func (x *TapConfigRequest) GetAllClients() bool { + if x != nil { + return x.AllClients + } + return false +} + +func (x *TapConfigRequest) GetTapSensThres() uint32 { + if x != nil { + return x.TapSensThres + } + return 0 +} + +func (x *TapConfigRequest) GetMaxGestDur() uint32 { + if x != nil { + return x.MaxGestDur + } + return 0 +} + +func (x *TapConfigRequest) GetTapShockDur() uint32 { + if x != nil { + return x.TapShockDur + } + return 0 +} + +func (x *TapConfigRequest) GetQuiteTimeAfterGest() uint32 { + if x != nil { + return x.QuiteTimeAfterGest + } + return 0 +} + +func (x *TapConfigRequest) GetWaitForTimeout() uint32 { + if x != nil { + return x.WaitForTimeout + } + return 0 +} + +func (x *TapConfigRequest) GetAxisSel() uint32 { + if x != nil { + return x.AxisSel + } + return 0 +} + +func (x *TapConfigRequest) GetEnableSingle() bool { + if x != nil { + return x.EnableSingle + } + return false +} + +func (x *TapConfigRequest) GetEnableDouble() bool { + if x != nil { + return x.EnableDouble + } + return false +} + +func (x *TapConfigRequest) GetEnableTriple() bool { + if x != nil { + return x.EnableTriple + } + return false +} + +type TapConfigResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + ClientId uint32 `protobuf:"varint,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` + Success bool `protobuf:"varint,2,opt,name=success,proto3" json:"success,omitempty"` + SlavesUpdated uint32 `protobuf:"varint,3,opt,name=slaves_updated,json=slavesUpdated,proto3" json:"slaves_updated,omitempty"` + TapSensThres uint32 `protobuf:"varint,4,opt,name=tap_sens_thres,json=tapSensThres,proto3" json:"tap_sens_thres,omitempty"` + MaxGestDur uint32 `protobuf:"varint,5,opt,name=max_gest_dur,json=maxGestDur,proto3" json:"max_gest_dur,omitempty"` + TapShockDur uint32 `protobuf:"varint,6,opt,name=tap_shock_dur,json=tapShockDur,proto3" json:"tap_shock_dur,omitempty"` + QuiteTimeAfterGest uint32 `protobuf:"varint,7,opt,name=quite_time_after_gest,json=quiteTimeAfterGest,proto3" json:"quite_time_after_gest,omitempty"` + WaitForTimeout uint32 `protobuf:"varint,8,opt,name=wait_for_timeout,json=waitForTimeout,proto3" json:"wait_for_timeout,omitempty"` + AxisSel uint32 `protobuf:"varint,9,opt,name=axis_sel,json=axisSel,proto3" json:"axis_sel,omitempty"` + EnableSingle bool `protobuf:"varint,10,opt,name=enable_single,json=enableSingle,proto3" json:"enable_single,omitempty"` + EnableDouble bool `protobuf:"varint,11,opt,name=enable_double,json=enableDouble,proto3" json:"enable_double,omitempty"` + EnableTriple bool `protobuf:"varint,12,opt,name=enable_triple,json=enableTriple,proto3" json:"enable_triple,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TapConfigResponse) Reset() { + *x = TapConfigResponse{} + mi := &file_uart_messages_proto_msgTypes[38] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TapConfigResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TapConfigResponse) ProtoMessage() {} + +func (x *TapConfigResponse) ProtoReflect() protoreflect.Message { + mi := &file_uart_messages_proto_msgTypes[38] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TapConfigResponse.ProtoReflect.Descriptor instead. +func (*TapConfigResponse) Descriptor() ([]byte, []int) { + return file_uart_messages_proto_rawDescGZIP(), []int{38} +} + +func (x *TapConfigResponse) GetClientId() uint32 { + if x != nil { + return x.ClientId + } + return 0 +} + +func (x *TapConfigResponse) GetSuccess() bool { + if x != nil { + return x.Success + } + return false +} + +func (x *TapConfigResponse) GetSlavesUpdated() uint32 { + if x != nil { + return x.SlavesUpdated + } + return 0 +} + +func (x *TapConfigResponse) GetTapSensThres() uint32 { + if x != nil { + return x.TapSensThres + } + return 0 +} + +func (x *TapConfigResponse) GetMaxGestDur() uint32 { + if x != nil { + return x.MaxGestDur + } + return 0 +} + +func (x *TapConfigResponse) GetTapShockDur() uint32 { + if x != nil { + return x.TapShockDur + } + return 0 +} + +func (x *TapConfigResponse) GetQuiteTimeAfterGest() uint32 { + if x != nil { + return x.QuiteTimeAfterGest + } + return 0 +} + +func (x *TapConfigResponse) GetWaitForTimeout() uint32 { + if x != nil { + return x.WaitForTimeout + } + return 0 +} + +func (x *TapConfigResponse) GetAxisSel() uint32 { + if x != nil { + return x.AxisSel + } + return 0 +} + +func (x *TapConfigResponse) GetEnableSingle() bool { + if x != nil { + return x.EnableSingle + } + return false +} + +func (x *TapConfigResponse) GetEnableDouble() bool { + if x != nil { + return x.EnableDouble + } + return false +} + +func (x *TapConfigResponse) GetEnableTriple() bool { + if x != nil { + return x.EnableTriple + } + return false +} + // Host → device: begin UART OTA (erase inactive OTA slot; device replies OTA_STATUS). type OtaStartPayload struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -3061,7 +3363,7 @@ type OtaStartPayload struct { func (x *OtaStartPayload) Reset() { *x = OtaStartPayload{} - mi := &file_uart_messages_proto_msgTypes[37] + mi := &file_uart_messages_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3073,7 +3375,7 @@ func (x *OtaStartPayload) String() string { func (*OtaStartPayload) ProtoMessage() {} func (x *OtaStartPayload) 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 { @@ -3086,7 +3388,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{37} + return file_uart_messages_proto_rawDescGZIP(), []int{39} } func (x *OtaStartPayload) GetTotalSize() uint32 { @@ -3107,7 +3409,7 @@ type OtaPayload struct { func (x *OtaPayload) Reset() { *x = OtaPayload{} - mi := &file_uart_messages_proto_msgTypes[38] + mi := &file_uart_messages_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3119,7 +3421,7 @@ func (x *OtaPayload) String() string { func (*OtaPayload) ProtoMessage() {} func (x *OtaPayload) 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 { @@ -3132,7 +3434,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{38} + return file_uart_messages_proto_rawDescGZIP(), []int{40} } func (x *OtaPayload) GetSeq() uint32 { @@ -3158,7 +3460,7 @@ type OtaEndPayload struct { func (x *OtaEndPayload) Reset() { *x = OtaEndPayload{} - mi := &file_uart_messages_proto_msgTypes[39] + mi := &file_uart_messages_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3170,7 +3472,7 @@ func (x *OtaEndPayload) String() string { func (*OtaEndPayload) ProtoMessage() {} func (x *OtaEndPayload) 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 { @@ -3183,7 +3485,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{39} + return file_uart_messages_proto_rawDescGZIP(), []int{41} } // Device → host status (also used as ACK after each 4 KiB written). @@ -3200,7 +3502,7 @@ type OtaStatusPayload struct { func (x *OtaStatusPayload) Reset() { *x = OtaStatusPayload{} - mi := &file_uart_messages_proto_msgTypes[40] + mi := &file_uart_messages_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3212,7 +3514,7 @@ func (x *OtaStatusPayload) String() string { func (*OtaStatusPayload) ProtoMessage() {} func (x *OtaStatusPayload) 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 { @@ -3225,7 +3527,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{40} + return file_uart_messages_proto_rawDescGZIP(), []int{42} } func (x *OtaStatusPayload) GetStatus() uint32 { @@ -3266,7 +3568,7 @@ type OtaSlaveProgressRequest struct { func (x *OtaSlaveProgressRequest) Reset() { *x = OtaSlaveProgressRequest{} - mi := &file_uart_messages_proto_msgTypes[41] + mi := &file_uart_messages_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3278,7 +3580,7 @@ func (x *OtaSlaveProgressRequest) String() string { func (*OtaSlaveProgressRequest) ProtoMessage() {} func (x *OtaSlaveProgressRequest) 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 { @@ -3291,7 +3593,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{41} + return file_uart_messages_proto_rawDescGZIP(), []int{43} } func (x *OtaSlaveProgressRequest) GetClientId() uint32 { @@ -3315,7 +3617,7 @@ type OtaSlaveProgressEntry struct { func (x *OtaSlaveProgressEntry) Reset() { *x = OtaSlaveProgressEntry{} - mi := &file_uart_messages_proto_msgTypes[42] + mi := &file_uart_messages_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3327,7 +3629,7 @@ func (x *OtaSlaveProgressEntry) String() string { func (*OtaSlaveProgressEntry) ProtoMessage() {} func (x *OtaSlaveProgressEntry) ProtoReflect() protoreflect.Message { - mi := &file_uart_messages_proto_msgTypes[42] + mi := &file_uart_messages_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3340,7 +3642,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{42} + return file_uart_messages_proto_rawDescGZIP(), []int{44} } func (x *OtaSlaveProgressEntry) GetClientId() uint32 { @@ -3391,7 +3693,7 @@ type OtaSlaveProgressResponse struct { func (x *OtaSlaveProgressResponse) Reset() { *x = OtaSlaveProgressResponse{} - mi := &file_uart_messages_proto_msgTypes[43] + mi := &file_uart_messages_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3403,7 +3705,7 @@ func (x *OtaSlaveProgressResponse) String() string { func (*OtaSlaveProgressResponse) ProtoMessage() {} func (x *OtaSlaveProgressResponse) ProtoReflect() protoreflect.Message { - mi := &file_uart_messages_proto_msgTypes[43] + mi := &file_uart_messages_proto_msgTypes[45] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3416,7 +3718,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{43} + return file_uart_messages_proto_rawDescGZIP(), []int{45} } func (x *OtaSlaveProgressResponse) GetActive() bool { @@ -3458,7 +3760,7 @@ var File_uart_messages_proto protoreflect.FileDescriptor const file_uart_messages_proto_rawDesc = "" + "\n" + - "\x13uart_messages.proto\x12\x04alox\x1a\fnanopb.proto\"\xc0\x14\n" + + "\x13uart_messages.proto\x12\x04alox\x1a\fnanopb.proto\"\xd3\x15\n" + "\vUartMessage\x12%\n" + "\x04type\x18\x01 \x01(\x0e2\x11.alox.MessageTypeR\x04type\x12,\n" + "\vack_payload\x18\x02 \x01(\v2\t.alox.AckH\x00R\n" + @@ -3497,7 +3799,9 @@ const file_uart_messages_proto_rawDesc = "" + "\x18espnow_echo_ping_request\x18# \x01(\v2\x1b.alox.EspNowEchoPingRequestH\x00R\x15espnowEchoPingRequest\x12Y\n" + "\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" + + "\x16set_log_level_response\x18& \x01(\v2\x19.alox.SetLogLevelResponseH\x00R\x13setLogLevelResponse\x12F\n" + + "\x12tap_config_request\x18' \x01(\v2\x16.alox.TapConfigRequestH\x00R\x10tapConfigRequest\x12I\n" + + "\x13tap_config_response\x18( \x01(\v2\x17.alox.TapConfigResponseH\x00R\x11tapConfigResponseB\t\n" + "\apayload\"\x05\n" + "\x03Ack\"!\n" + "\vEchoPayload\x12\x12\n" + @@ -3666,7 +3970,38 @@ const file_uart_messages_proto_rawDesc = "" + "\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" + + "\x05level\x18\x02 \x01(\rR\x05level\"\xb9\x03\n" + + "\x10TapConfigRequest\x12\x14\n" + + "\x05write\x18\x01 \x01(\bR\x05write\x12\x1b\n" + + "\tclient_id\x18\x02 \x01(\rR\bclientId\x12\x1f\n" + + "\vall_clients\x18\x03 \x01(\bR\n" + + "allClients\x12$\n" + + "\x0etap_sens_thres\x18\x04 \x01(\rR\ftapSensThres\x12 \n" + + "\fmax_gest_dur\x18\x05 \x01(\rR\n" + + "maxGestDur\x12\"\n" + + "\rtap_shock_dur\x18\x06 \x01(\rR\vtapShockDur\x121\n" + + "\x15quite_time_after_gest\x18\a \x01(\rR\x12quiteTimeAfterGest\x12(\n" + + "\x10wait_for_timeout\x18\b \x01(\rR\x0ewaitForTimeout\x12\x19\n" + + "\baxis_sel\x18\t \x01(\rR\aaxisSel\x12#\n" + + "\renable_single\x18\n" + + " \x01(\bR\fenableSingle\x12#\n" + + "\renable_double\x18\v \x01(\bR\fenableDouble\x12#\n" + + "\renable_triple\x18\f \x01(\bR\fenableTriple\"\xc4\x03\n" + + "\x11TapConfigResponse\x12\x1b\n" + + "\tclient_id\x18\x01 \x01(\rR\bclientId\x12\x18\n" + + "\asuccess\x18\x02 \x01(\bR\asuccess\x12%\n" + + "\x0eslaves_updated\x18\x03 \x01(\rR\rslavesUpdated\x12$\n" + + "\x0etap_sens_thres\x18\x04 \x01(\rR\ftapSensThres\x12 \n" + + "\fmax_gest_dur\x18\x05 \x01(\rR\n" + + "maxGestDur\x12\"\n" + + "\rtap_shock_dur\x18\x06 \x01(\rR\vtapShockDur\x121\n" + + "\x15quite_time_after_gest\x18\a \x01(\rR\x12quiteTimeAfterGest\x12(\n" + + "\x10wait_for_timeout\x18\b \x01(\rR\x0ewaitForTimeout\x12\x19\n" + + "\baxis_sel\x18\t \x01(\rR\aaxisSel\x12#\n" + + "\renable_single\x18\n" + + " \x01(\bR\fenableSingle\x12#\n" + + "\renable_double\x18\v \x01(\bR\fenableDouble\x12#\n" + + "\renable_triple\x18\f \x01(\bR\fenableTriple\"0\n" + "\x0fOtaStartPayload\x12\x1d\n" + "\n" + "total_size\x18\x01 \x01(\rR\ttotalSize\":\n" + @@ -3697,7 +4032,7 @@ const file_uart_messages_proto_rawDesc = "" + "\x0faggregate_bytes\x18\x03 \x01(\rR\x0eaggregateBytes\x12\x1f\n" + "\vslave_count\x18\x04 \x01(\rR\n" + "slaveCount\x12:\n" + - "\x06slaves\x18\x05 \x03(\v2\x1b.alox.OtaSlaveProgressEntryB\x05\x92?\x02\x10\x10R\x06slaves*\x9a\x03\n" + + "\x06slaves\x18\x05 \x03(\v2\x1b.alox.OtaSlaveProgressEntryB\x05\x92?\x02\x10\x10R\x06slaves*\xaa\x03\n" + "\vMessageType\x12\v\n" + "\aUNKNOWN\x10\x00\x12\a\n" + "\x03ACK\x10\x01\x12\b\n" + @@ -3723,7 +4058,9 @@ const file_uart_messages_proto_rawDesc = "" + "TAP_NOTIFY\x10\x1b\x12\x10\n" + "\fCACHE_STATUS\x10\x1d\x12\x14\n" + "\x10ESPNOW_ECHO_PING\x10\x1e\x12\x11\n" + - "\rSET_LOG_LEVEL\x10\x1f\"\x04\b\x18\x10\x18\"\x04\b\x1c\x10\x1c*G\n" + + "\rSET_LOG_LEVEL\x10\x1f\x12\x0e\n" + + "\n" + + "TAP_CONFIG\x10 \"\x04\b\x18\x10\x18\"\x04\b\x1c\x10\x1c*G\n" + "\aTapKind\x12\f\n" + "\bTAP_NONE\x10\x00\x12\x0e\n" + "\n" + @@ -3746,7 +4083,7 @@ func file_uart_messages_proto_rawDescGZIP() []byte { } var file_uart_messages_proto_enumTypes = make([]protoimpl.EnumInfo, 2) -var file_uart_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 44) +var file_uart_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 46) var file_uart_messages_proto_goTypes = []any{ (MessageType)(0), // 0: alox.MessageType (TapKind)(0), // 1: alox.TapKind @@ -3787,13 +4124,15 @@ var file_uart_messages_proto_goTypes = []any{ (*RestartResponse)(nil), // 36: alox.RestartResponse (*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 + (*TapConfigRequest)(nil), // 39: alox.TapConfigRequest + (*TapConfigResponse)(nil), // 40: alox.TapConfigResponse + (*OtaStartPayload)(nil), // 41: alox.OtaStartPayload + (*OtaPayload)(nil), // 42: alox.OtaPayload + (*OtaEndPayload)(nil), // 43: alox.OtaEndPayload + (*OtaStatusPayload)(nil), // 44: alox.OtaStatusPayload + (*OtaSlaveProgressRequest)(nil), // 45: alox.OtaSlaveProgressRequest + (*OtaSlaveProgressEntry)(nil), // 46: alox.OtaSlaveProgressEntry + (*OtaSlaveProgressResponse)(nil), // 47: alox.OtaSlaveProgressResponse } var file_uart_messages_proto_depIdxs = []int32{ 0, // 0: alox.UartMessage.type:type_name -> alox.MessageType @@ -3802,16 +4141,16 @@ var file_uart_messages_proto_depIdxs = []int32{ 5, // 3: alox.UartMessage.version_response:type_name -> alox.VersionResponse 7, // 4: alox.UartMessage.client_info_response:type_name -> alox.ClientInfoResponse 9, // 5: alox.UartMessage.client_input_response:type_name -> alox.ClientInputResponse - 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 + 41, // 6: alox.UartMessage.ota_start:type_name -> alox.OtaStartPayload + 42, // 7: alox.UartMessage.ota_payload:type_name -> alox.OtaPayload + 43, // 8: alox.UartMessage.ota_end:type_name -> alox.OtaEndPayload + 44, // 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 - 43, // 14: alox.UartMessage.ota_slave_progress_request:type_name -> alox.OtaSlaveProgressRequest - 45, // 15: alox.UartMessage.ota_slave_progress_response:type_name -> alox.OtaSlaveProgressResponse + 45, // 14: alox.UartMessage.ota_slave_progress_request:type_name -> alox.OtaSlaveProgressRequest + 47, // 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 @@ -3830,22 +4169,24 @@ var file_uart_messages_proto_depIdxs = []int32{ 30, // 31: alox.UartMessage.espnow_echo_ping_response:type_name -> alox.EspNowEchoPingResponse 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 + 39, // 34: alox.UartMessage.tap_config_request:type_name -> alox.TapConfigRequest + 40, // 35: alox.UartMessage.tap_config_response:type_name -> alox.TapConfigResponse + 6, // 36: alox.ClientInfoResponse.clients:type_name -> alox.ClientInfo + 8, // 37: alox.ClientInputResponse.clients:type_name -> alox.ClientInput + 15, // 38: alox.BatterySample.lipo1:type_name -> alox.LipoReading + 15, // 39: alox.BatterySample.lipo2:type_name -> alox.LipoReading + 16, // 40: alox.BatteryStatusResponse.samples:type_name -> alox.BatterySample + 1, // 41: alox.TapEvent.kind:type_name -> alox.TapKind + 1, // 42: alox.CacheClientTap.kind:type_name -> alox.TapKind + 23, // 43: alox.CacheClientStatus.accel:type_name -> alox.CacheClientAccel + 24, // 44: alox.CacheClientStatus.tap:type_name -> alox.CacheClientTap + 25, // 45: alox.CacheStatusResponse.clients:type_name -> alox.CacheClientStatus + 46, // 46: alox.OtaSlaveProgressResponse.slaves:type_name -> alox.OtaSlaveProgressEntry + 47, // [47:47] is the sub-list for method output_type + 47, // [47:47] is the sub-list for method input_type + 47, // [47:47] is the sub-list for extension type_name + 47, // [47:47] is the sub-list for extension extendee + 0, // [0:47] is the sub-list for field type_name } func init() { file_uart_messages_proto_init() } @@ -3887,6 +4228,8 @@ func file_uart_messages_proto_init() { (*UartMessage_EspnowEchoPingResponse)(nil), (*UartMessage_SetLogLevelRequest)(nil), (*UartMessage_SetLogLevelResponse)(nil), + (*UartMessage_TapConfigRequest)(nil), + (*UartMessage_TapConfigResponse)(nil), } type x struct{} out := protoimpl.TypeBuilder{ @@ -3894,7 +4237,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: 44, + NumMessages: 46, NumExtensions: 0, NumServices: 0, }, diff --git a/goTool/webui/index.html b/goTool/webui/index.html index 062ba01..4e345cd 100644 --- a/goTool/webui/index.html +++ b/goTool/webui/index.html @@ -291,6 +291,69 @@ Setzen +
Tap-Erkennung (BMA456)
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ + + + + +

UART nicht verbunden — Eingabe gesperrt.

@@ -313,6 +376,12 @@ :disabled="busy || !state.uart_connected"> Alle Slaves + @@ -348,6 +417,7 @@ Ver Status Deadzone + Tap-Cfg Accel (LSB) Akku Accel @@ -358,7 +428,7 @@