fix(sensing-server): accept vendor --source values and bind UDP for them

The previous commit limited --source to auto/esp32/wifi/simulated, which
rejected the vendor names the server already keys on: mediatek, qualcomm,
realtek (RTL8720F radar) and realtek_csi (RTL8721Dx CSI). They are the
labels the UDP receiver writes and effective_source() ages.

On 03a89793 those names fell into the catch-all plan, which bound no UDP
receiver, so vendor frames were never ingested. They now plan like esp32
(UDP receiver bound) without the ESP32-shaped simulator. Anything else,
including case variants and runtime-only labels like "mediatek:simulated",
is still rejected.

Refs #2097

Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
Mathew Beaneandclaude-flow committed 2026-10-02 22:13:38 -04:00
1 parent 5755d9f11f
commit 5cffe9e7db
2 files changed
+68 -5

No files matched your search

+4 -2
View File
@@ -303,7 +303,9 @@ All endpoints return JSON. In simulated mode, data is generated from a determini
## Data Sources
The `--source` flag controls where CSI data comes from. Valid values are
`auto`, `esp32`, `wifi`, and `simulated` (alias `simulate`). Any other value
`auto`, `esp32`, `wifi`, and `simulated` (alias `simulate`), plus the vendor
feeds `mediatek`, `qualcomm`, `realtek` (RTL8720F radar), and `realtek_csi`
(RTL8721Dx CSI), which bind the UDP receiver like `esp32`. Any other value
stops the server at startup with an error that lists them.
### Simulated Mode (No Hardware)
@@ -1287,7 +1289,7 @@ The Rust sensing server binary accepts the following flags:
| Flag | Default | Description |
|------|---------|-------------|
| `--source` | `auto` | Data source: `auto`, `esp32`, `wifi`, `simulated` (alias `simulate`). Other values are rejected at startup |
| `--source` | `auto` | Data source: `auto`, `esp32`, `wifi`, `simulated` (alias `simulate`), `mediatek`, `qualcomm`, `realtek`, `realtek_csi`. Other values are rejected at startup |
| `--http-port` | `8080` | HTTP port for REST API and UI |
| `--ws-port` | `8765` | WebSocket port |
| `--udp-port` | `5005` | UDP port for ESP32 CSI frames |
@@ -4659,8 +4659,20 @@ struct SourcePlan {
/// Every `--source` value [`plan_source`] accepts. Clap rejects anything else
/// at startup (issue #2097): an unknown value used to start the server with no
/// data task while `/api/v1/status` still reported a live source.
const SOURCE_VALUES: [&str; 5] = ["auto", "esp32", "wifi", "simulated", "simulate"];
/// data task while `/api/v1/status` still reported a live source. The vendor
/// names match the labels the UDP receiver writes for MTC1, RAC1, Qualcomm
/// and RTL8720F radar frames, so `effective_source()` ages them correctly.
const SOURCE_VALUES: [&str; 9] = [
"auto",
"esp32",
"wifi",
"simulated",
"simulate",
"mediatek",
"qualcomm",
"realtek",
"realtek_csi",
];
/// Pure decision function — fully unit-testable without binding sockets.
///
@@ -4721,6 +4733,16 @@ fn plan_source(
run_simulator: false,
run_wifi: true,
},
// Vendor CSI and radar frames arrive on the same UDP receiver as ESP32
// frames. Before #2097 these names fell into a catch-all that bound no
// receiver, so nothing was ever ingested. Never run the ESP32-shaped
// simulator alongside a vendor feed.
"mediatek" | "qualcomm" | "realtek" | "realtek_csi" => SourcePlan {
initial_source: requested.to_string(),
bind_udp: true,
run_simulator: false,
run_wifi: false,
},
other => {
return Err(format!(
"unknown --source '{other}' (valid values: {})",
@@ -4924,9 +4946,48 @@ mod issue_2097_status_tests {
}
}
#[test]
fn vendor_sources_bind_the_udp_receiver() {
for vendor in ["mediatek", "qualcomm", "realtek", "realtek_csi"] {
let plan = plan_source(vendor, false, false).expect("vendor source plans");
assert!(plan.bind_udp, "{vendor}: vendor frames arrive over UDP");
assert!(!plan.run_simulator, "{vendor}: no ESP32-shaped simulator");
assert!(!plan.run_wifi);
assert_eq!(plan.initial_source, vendor);
}
}
#[test]
fn only_garbage_is_rejected() {
for bogus in [
"bogus",
"macos",
"linux",
"mock",
"MEDIATEK",
"mediatek:simulated",
"esp32 ",
] {
assert!(
Args::try_parse_from(["sensing-server", "--source", bogus]).is_err(),
"--source {bogus:?} must be rejected"
);
}
}
#[test]
fn every_documented_source_still_parses() {
for source in ["auto", "esp32", "wifi", "simulated", "simulate"] {
for source in [
"auto",
"esp32",
"wifi",
"simulated",
"simulate",
"mediatek",
"qualcomm",
"realtek",
"realtek_csi",
] {
let args = Args::try_parse_from(["sensing-server", "--source", source])
.unwrap_or_else(|e| panic!("--source {source} must parse: {e}"));
assert_eq!(args.source, source);