Draw real telemetry from the car, not a hardcoded literal - #3
Conversation
1497fcb to
54c429f
Compare
The dashboard has always run off a struct literal in main.c with a demo
loop on top. There was no way to show what the car is actually doing.
It now reads live packets through the SensorHub library and falls back to
the demo when no serial device is present, so the simulator still works on
a laptop with nothing attached. Pass a device to go live:
./bin/main /dev/ttyUSB0
Which physical channel carries what is now an explicit struct in
telemetry_source.c rather than a JSON file that both a git pull and an
MQTT message could rewrite behind your back, which is how the old Python
server lost its channel names in April.
engine_armed and engine_on are deliberately left unmapped. The dashboard
has drawn indicators for them since it was written, but no channel has
ever carried them, so they have been dark in every run so far. Guessing a
pin would replace a dark light with a confidently wrong one; the mapping
is one line once someone confirms the wiring.
Two incidental fixes the new CI forced out: .gitignore was swallowing
.github/, so no workflow could ever be committed, and the lap label's
buffer was one byte short of what a full int can print.
54c429f to
3b99255
Compare
The dashboard has always run off a struct literal in main.c with a demo
loop on top. There was no way to show what the car is actually doing.
It now reads live packets through the SensorHub library and falls back to
the demo when no serial device is present, so the simulator still works on
a laptop with nothing attached. Pass a device to go live:
./bin/main /dev/ttyUSB0
Which physical channel carries what is now an explicit struct in
telemetry_source.c rather than a JSON file that both a git pull and an
MQTT message could rewrite behind your back, which is how the old Python
server lost its channel names in April.
engine_armed and engine_on are deliberately left unmapped. The dashboard
has drawn indicators for them since it was written, but no channel has
ever carried them, so they have been dark in every run so far. Guessing a
pin would replace a dark light with a confidently wrong one; the mapping
is one line once someone confirms the wiring.
Two incidental fixes the new CI forced out: .gitignore was swallowing
.github/, so no workflow could ever be committed, and the lap label's
buffer was one byte short of what a full int can print.
|
Updated: the wire format now carries a version and a length byte from the start, rather than being retrofitted later. The version byte exists for one specific failure. If the payload changes size, framing desyncs and you notice. But if it stays the same size and a field changes meaning, the checksum still passes and the receiver decodes confidently wrong data. That is exactly what happened on the Python side in April, when columns 5 and 6 silently went from The length byte lets an old receiver skip a packet from a newer sender and stay framed instead of desynchronising. Payload also widened while it was cheap to do so, since breaking the format twice is much worse than once:
Outputs are reported now. The firmware drives a radiator fan and a water pump whose state appeared nowhere in telemetry, so there was no way to see or log what the car was doing to itself. The sequence number makes dropped packets visible. A checksum cannot tell you about a packet that never arrived, so a link losing half its traffic looked identical to a healthy one. Costs: frame 26 to 41 bytes, which takes the link from 4.5% to 7% utilisation, and the sketch from 18% to 19% of a Nano. |
Why
The dashboard has always run off a struct literal in
main.cwith a demo loop on top. There was no way to show what the car is actually doing.What changed
It now reads live packets through the SensorHub library, and falls back to the demo when no serial device is present, so the simulator still works on a laptop with nothing attached:
The demo loop moved into
telemetry_source.calongside the live path, so the dashboard has exactly one way in regardless of whether a car is attached.Channel mapping is now explicit code. The Arduino sends anonymous
channel0..4andchannelA0; what they mean is a wiring decision. The old Python server kept that in a JSON file undertest/that both agit pulland an MQTT message could rewrite, and in April a pull silently changed the column names mid-season. Here it is a struct you can read next to the code that depends on it.distance_ftis integrated from speed, since the packet carries no odometer. It therefore restarts at zero whenever the process does, which is worth knowing before trusting it mid-run.What I deliberately did not do
engine_armedandengine_onare left unmapped. The dashboard has drawn indicators for them since it was written, but no channel has ever carried them, and the old Python config never defined them either, so those lights have been dark in every run so far. The firmware README describes channels 3 and 4 as "switch pins" and 0 and 1 as "currently user input", which is not enough to pick from.Guessing would replace a dark light with a confidently wrong one. It is a one-line change once someone confirms the wiring, and
channel0,2,3, and4are all still free.Build
SensorHub is optional on purpose, so this still builds standalone:
An explicit path that does not resolve is a hard error rather than a silent fallback, since quietly building demo-only would look identical to success.
CI
Host simulator on Linux and macOS, a warnings-as-errors pass over our sources, and both build modes. The live build checks with
nmthat the SensorHub symbols are genuinely linked, because a silent fallback to demo would otherwise pass.There is also a startup smoke test that runs the binary under Xvfb for five seconds. LVGL will happily compile and then abort at runtime on a bad config, which a compile check never catches.
One incidental fix
.gitignorehad.*/under a comment promising "below exceptions" and then listed none, so.github/was swallowed and no workflow could ever be committed. Added the exception.Order
Needs HEEV/SensorHub#2 to merge first; CI here checks it out from
main.