Vcu mode set over can#307
Conversation
New Pi->VCU CAN packet so the VCU's params table (acceleration/skidpad/
autocross/endurance) can be selected at runtime over CAN instead of the
compile-time SELECTED_PARAMS #define. 8 bytes for extensibility; byte0 =
event_mode (1=accel 2=skid 3=autox 4=endur), bytes 1-7 reserved.
Regenerated C drivers (can_ids.h/.c) give the VCU VCU_MODE_COMMAND_ID,
msg_vcu_mode_command_t{event_mode}, and unpack_vcu_mode_command() to wire a
receive handler against. Command packet => no telemetry/proto/SQL changes.
Regen chain: update_can_proto.py + sync_assets.sh + sync_schema.sh +
generate_can_lib.py (CI schema-drift chain + the VCU C-driver gen).
cand: add a single-writer CAN transmit thread on can0 (critical bus, where the VCU listens). It owns the only write socket and serves /tmp/BEVO_cand_tx.sock; clients send 13-byte frame requests (u32 LE id, u8 dlc, 8 data bytes). Keeps cand the sole CAN writer. dashd: on lhre/dash/eventMode, relay the value to cand as the 0x029 VCU Mode Command frame (byte0=event_mode) and ack on lhre/dash/ack/eventMode. dashd doesn't interpret the mode; the VCU re-broadcasts event_mode in 0x1C7 which trackside already reads back as confirmation.
dashSignals.publishEventMode(mode) publishes lhre/dash/eventMode (qos 1); a new 'VCU Mode' panel on the Dash tab lets the strategist pick Acceleration/Skidpad/ Autocross/Endurance and send it. dashd relays it onto CAN as 0x029, the VCU applies + re-broadcasts its mode, closing the loop with the existing MODE read.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Code Review
This pull request introduces a single-writer CAN transmit path to allow trackside VCU mode commands (0x029) to be relayed from MQTT to the critical CAN bus via dashd and cand. It also updates the telemetry frontend to provide a UI panel for selecting and sending these modes. The review comments point out two important issues: a potential truncation bug in cand when casting CAN IDs to u16 without validating standard bounds, and unsafe parsing of localStorage values in the frontend without validating against allowed VCU modes.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| let sid = match StandardId::new(id as u16) { | ||
| Some(s) => s, | ||
| None => { | ||
| eprintln!("[CAND-TX] rejecting non-standard CAN id {:#x}", id); | ||
| continue; | ||
| } | ||
| }; |
There was a problem hiding this comment.
Casting id as u16 directly can lead to silent truncation bugs if the client sends an ID greater than 0xFFFF or an extended CAN ID (which are 29-bit). For example, 0x10005 would be truncated to 5, which is a valid standard ID, and thus sent incorrectly. We should explicitly check that id is within the valid standard CAN ID range (<= 0x7FF) before attempting to construct the StandardId.
let sid = if id <= 0x7FF {
StandardId::new(id as u16)
} else {
None
};
let sid = match sid {
Some(s) => s,
None => {
eprintln!("[CAND-TX] rejecting non-standard CAN id {:#x}", id);
continue;
}
};| const [dashPowerMode, setDashPowerMode] = useState<"auto" | "manual">(() => (localStorage.getItem("dash-power-mode") === "manual" ? "manual" : "auto")); | ||
| const [dashAutoLap, setDashAutoLap] = useState(() => localStorage.getItem("dash-auto-lap") === "1"); | ||
| // Selected VCU params table to command (event_mode); persisted for convenience. | ||
| const [vcuMode, setVcuMode] = useState<number>(() => Number(localStorage.getItem("dash-vcu-mode") || 4)); |
There was a problem hiding this comment.
Parsing localStorage values directly using Number(...) can be unsafe if the stored value is corrupted, empty, or not a valid mode number (e.g., resulting in NaN or an out-of-bounds value like 0 or 5). It is safer to parse the value and validate that it is one of the allowed VCU modes (1, 2, 3, or 4), defaulting to 4 (Endurance) if invalid.
const [vcuMode, setVcuMode] = useState<number>(() => {
const saved = localStorage.getItem("dash-vcu-mode");
const parsed = saved ? Number(saved) : 4;
return [1, 2, 3, 4].includes(parsed) ? parsed : 4;
});
|
@matt-mekha Add your VCU side code to this branch. I also updated the schema assets which seemed to have picked up HVC stuff so those are also shown as additions in this PR. |
- cand: range-check id <= 0x7FF before 'id as u16' so an extended/>16-bit id (e.g. 0x10005) can't silently truncate (-> 0x5) and transmit to the wrong node (Gemini, high). - trackside: validate the localStorage vcuMode is one of 1-4, else default 4, so a corrupted/empty value can't preselect an invalid mode (Gemini, medium).
Added CAN from BEVO to tell VCU what mode we want it and updated trackside front end to allow runtime changes.