Add selectable ESP-NOW send path for accel/tap input.
Expose best_effort/fast/wait/reliable via UART, dashboard, and CLI so loss vs latency can be compared under real multi-pod load. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
pb "powerpod/gotool/pb"
|
||||
)
|
||||
|
||||
type inputSendModeAPIResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Mode uint32 `json:"mode"`
|
||||
ModeName string `json:"mode_name"`
|
||||
ClientID uint32 `json:"client_id,omitempty"`
|
||||
SlavesUpdated uint32 `json:"slaves_updated,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func inputSendModeName(mode pb.InputSendMode) string {
|
||||
switch mode {
|
||||
case pb.InputSendMode_INPUT_SEND_BEST_EFFORT:
|
||||
return "best_effort"
|
||||
case pb.InputSendMode_INPUT_SEND_FAST:
|
||||
return "fast"
|
||||
case pb.InputSendMode_INPUT_SEND_WAIT:
|
||||
return "wait"
|
||||
case pb.InputSendMode_INPUT_SEND_RELIABLE:
|
||||
return "reliable"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
func mountInputSendModeAPI(mux *http.ServeMux, link *managedSerial) {
|
||||
mux.HandleFunc("/api/input-send-mode", func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
serveInputSendModeGet(w, link)
|
||||
case http.MethodPut, http.MethodPost:
|
||||
serveInputSendModePut(w, r, link)
|
||||
default:
|
||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func serveInputSendModeGet(w http.ResponseWriter, link *managedSerial) {
|
||||
resp, err := link.InputSendMode(&pb.InputSendModeRequest{Write: false})
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusBadGateway, inputSendModeAPIResponse{Error: err.Error()})
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, inputSendModeAPIResponse{
|
||||
Success: resp.GetSuccess(),
|
||||
Mode: uint32(resp.GetMode()),
|
||||
ModeName: inputSendModeName(resp.GetMode()),
|
||||
})
|
||||
}
|
||||
|
||||
func serveInputSendModePut(w http.ResponseWriter, r *http.Request, link *managedSerial) {
|
||||
var body struct {
|
||||
Mode uint32 `json:"mode"`
|
||||
ClientID uint32 `json:"client_id"`
|
||||
AllClients bool `json:"all_clients"`
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
|
||||
writeJSON(w, http.StatusBadRequest, inputSendModeAPIResponse{Error: "invalid JSON"})
|
||||
return
|
||||
}
|
||||
if body.Mode > uint32(pb.InputSendMode_INPUT_SEND_RELIABLE) {
|
||||
writeJSON(w, http.StatusBadRequest, inputSendModeAPIResponse{Error: "mode must be 0..3"})
|
||||
return
|
||||
}
|
||||
if !body.AllClients && body.ClientID == 0 {
|
||||
// Dashboard default: apply to every registered slave.
|
||||
body.AllClients = true
|
||||
}
|
||||
|
||||
resp, err := link.InputSendMode(&pb.InputSendModeRequest{
|
||||
Write: true,
|
||||
Mode: pb.InputSendMode(body.Mode),
|
||||
ClientId: body.ClientID,
|
||||
AllClients: body.AllClients,
|
||||
})
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusBadGateway, inputSendModeAPIResponse{Error: err.Error()})
|
||||
return
|
||||
}
|
||||
status := http.StatusOK
|
||||
if !resp.GetSuccess() {
|
||||
status = http.StatusBadRequest
|
||||
}
|
||||
writeJSON(w, status, inputSendModeAPIResponse{
|
||||
Success: resp.GetSuccess(),
|
||||
Mode: uint32(resp.GetMode()),
|
||||
ModeName: inputSendModeName(resp.GetMode()),
|
||||
ClientID: resp.GetClientId(),
|
||||
SlavesUpdated: resp.GetSlavesUpdated(),
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user