package main import ( "encoding/json" "errors" "io" "net/http" "time" ) type bleRttAPIRequest struct { Count *int `json:"count"` Warmup *int `json:"warmup"` SettleS *float64 `json:"settle_s"` } type bleStreamAPIRequest struct { ClientID *uint32 `json:"client_id"` PeriodMs *uint32 `json:"period_ms"` Count *int `json:"count"` TolMs *float64 `json:"tol_ms"` TimeoutS *float64 `json:"timeout_s"` } func mountBleTestAPI(mux *http.ServeMux, link *managedHost) { mux.HandleFunc("/api/ble-rtt", func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "method not allowed", http.StatusMethodNotAllowed) return } serveBleRtt(w, r, link) }) mux.HandleFunc("/api/ble-stream", func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "method not allowed", http.StatusMethodNotAllowed) return } serveBleStreamTest(w, r, link) }) } func requireBLEHost(w http.ResponseWriter, link *managedHost) bool { if link.Transport() != hostTransportBLE || !link.IsConnected() { writeJSON(w, http.StatusBadRequest, bleRttResult{ Error: "BLE host required (connect via BLE, DIP8=1)", }) return false } return true } func serveBleRtt(w http.ResponseWriter, r *http.Request, link *managedHost) { if !requireBLEHost(w, link) { return } var body bleRttAPIRequest if err := json.NewDecoder(r.Body).Decode(&body); err != nil && !errors.Is(err, io.EOF) { writeJSON(w, http.StatusBadRequest, bleRttResult{Error: "invalid JSON"}) return } count, warmup := 50, 5 settle := 0.0 if body.Count != nil { count = *body.Count } if body.Warmup != nil { warmup = *body.Warmup } if body.SettleS != nil { settle = *body.SettleS } if !link.beginPausePoll() { writeJSON(w, http.StatusConflict, bleRttResult{Error: "host busy"}) return } defer link.endPausePoll() out := measureBleRtt(link, count, warmup, time.Duration(settle*float64(time.Second))) status := http.StatusOK if !out.Success { status = http.StatusBadRequest } writeJSON(w, status, out) } func serveBleStreamTest(w http.ResponseWriter, r *http.Request, link *managedHost) { if !requireBLEHost(w, link) { return } var body bleStreamAPIRequest if err := json.NewDecoder(r.Body).Decode(&body); err != nil && !errors.Is(err, io.EOF) { writeJSON(w, http.StatusBadRequest, bleStreamResult{Error: "invalid JSON"}) return } count := 50 periodMs := uint32(16) tolMs := 2.0 timeoutS := 15.0 var clientID uint32 if body.Count != nil { count = *body.Count } if body.PeriodMs != nil { periodMs = *body.PeriodMs } if body.TolMs != nil { tolMs = *body.TolMs } if body.TimeoutS != nil { timeoutS = *body.TimeoutS } if body.ClientID != nil { clientID = *body.ClientID } if !link.beginPausePoll() { writeJSON(w, http.StatusConflict, bleStreamResult{Error: "host busy"}) return } defer link.endPausePoll() out := measureBleStream(link, clientID, periodMs, count, tolMs, timeoutS) status := http.StatusOK if !out.Success { status = http.StatusBadRequest } writeJSON(w, status, out) }