Files
powerpods/goTool/api_input_send_mode.go
skrueckenandCursor 1adaddd6c8 Add selectable ESP-NOW send path for accel/tap input.
Expose best_effort/fast/wait/reliable via UART, dashboard, and CLI so
loss vs latency can be compared under real multi-pod load.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-11-01 22:34:03 +01:00

101 lines
2.8 KiB
Go

package main
import (
"encoding/json"
"net/http"
pb "powerpod/gotool/pb"
)
type inputSendModeAPIResponse struct {
Success bool `json:"success"`
Mode uint32 `json:"mode"`
ModeName string `json:"mode_name"`
ClientID uint32 `json:"client_id,omitempty"`
SlavesUpdated uint32 `json:"slaves_updated,omitempty"`
Error string `json:"error,omitempty"`
}
func inputSendModeName(mode pb.InputSendMode) string {
switch mode {
case pb.InputSendMode_INPUT_SEND_BEST_EFFORT:
return "best_effort"
case pb.InputSendMode_INPUT_SEND_FAST:
return "fast"
case pb.InputSendMode_INPUT_SEND_WAIT:
return "wait"
case pb.InputSendMode_INPUT_SEND_RELIABLE:
return "reliable"
default:
return "unknown"
}
}
func mountInputSendModeAPI(mux *http.ServeMux, link *managedSerial) {
mux.HandleFunc("/api/input-send-mode", func(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
serveInputSendModeGet(w, link)
case http.MethodPut, http.MethodPost:
serveInputSendModePut(w, r, link)
default:
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
}
})
}
func serveInputSendModeGet(w http.ResponseWriter, link *managedSerial) {
resp, err := link.InputSendMode(&pb.InputSendModeRequest{Write: false})
if err != nil {
writeJSON(w, http.StatusBadGateway, inputSendModeAPIResponse{Error: err.Error()})
return
}
writeJSON(w, http.StatusOK, inputSendModeAPIResponse{
Success: resp.GetSuccess(),
Mode: uint32(resp.GetMode()),
ModeName: inputSendModeName(resp.GetMode()),
})
}
func serveInputSendModePut(w http.ResponseWriter, r *http.Request, link *managedSerial) {
var body struct {
Mode uint32 `json:"mode"`
ClientID uint32 `json:"client_id"`
AllClients bool `json:"all_clients"`
}
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
writeJSON(w, http.StatusBadRequest, inputSendModeAPIResponse{Error: "invalid JSON"})
return
}
if body.Mode > uint32(pb.InputSendMode_INPUT_SEND_RELIABLE) {
writeJSON(w, http.StatusBadRequest, inputSendModeAPIResponse{Error: "mode must be 0..3"})
return
}
if !body.AllClients && body.ClientID == 0 {
// Dashboard default: apply to every registered slave.
body.AllClients = true
}
resp, err := link.InputSendMode(&pb.InputSendModeRequest{
Write: true,
Mode: pb.InputSendMode(body.Mode),
ClientId: body.ClientID,
AllClients: body.AllClients,
})
if err != nil {
writeJSON(w, http.StatusBadGateway, inputSendModeAPIResponse{Error: err.Error()})
return
}
status := http.StatusOK
if !resp.GetSuccess() {
status = http.StatusBadRequest
}
writeJSON(w, status, inputSendModeAPIResponse{
Success: resp.GetSuccess(),
Mode: uint32(resp.GetMode()),
ModeName: inputSendModeName(resp.GetMode()),
ClientID: resp.GetClientId(),
SlavesUpdated: resp.GetSlavesUpdated(),
})
}