Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
c9cc37a
cascadia.dbc: match TEL/MDI/DRD/STR firmware
clbears Nov 1, 2026
71c05ae
parser: make --dbc take effect and store enum signals as ints
clbears Nov 1, 2026
b62c336
Add Cascadia TEL, MDI, DRD and STR dashboards
clbears Nov 1, 2026
e2c6695
Add Cascadia CAN scenario simulator; dashboard polish
clbears Nov 1, 2026
666034f
cascadia_sim: browser control panel
clbears Nov 1, 2026
d69e0eb
cascadia_sim panel: stronger alarm red
clbears Nov 1, 2026
af96c4b
Cascadia dashboards: saturated alarm red, tiles fill red only when ab…
clbears Nov 1, 2026
5cde778
Cascadia dashboards: fault status tile per board
clbears Nov 1, 2026
9587ee8
Cascadia dashboards: tint fault rows instead of a status tile
clbears Nov 1, 2026
f6cd37d
Cascadia dashboards: full-width fault banner per board
clbears Nov 1, 2026
398b0c0
cascadia_sim: 'Reset everything to normal' clears fault history
clbears Nov 1, 2026
ea988af
Fault banner warnings; sim GPS fix follows satellite count
clbears Nov 1, 2026
d076bc5
Cascadia dashboards: collapsed Raw / diagnostic row per board
clbears Nov 1, 2026
9fd18eb
Screenshots for the Cascadia dashboards PR; cap simulated motor temp
clbears Nov 1, 2026
e14614c
cascadia_sim: tag simulated points, reset deletes only those
clbears Nov 1, 2026
8696d05
cascadia_sim: README on installing and running the simulator
clbears Nov 2, 2026
da02a4a
Revert parser changes (--dbc import, enum ints)
clbears Nov 3, 2026
6593af4
cascadia_sim: drop 'decoded the way the parser does'
clbears Nov 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,475 changes: 1,475 additions & 0 deletions dashboards/PROD/PROD_DRD_Cascadia.json

Large diffs are not rendered by default.

949 changes: 949 additions & 0 deletions dashboards/PROD/PROD_MDI_Cascadia.json

Large diffs are not rendered by default.

809 changes: 809 additions & 0 deletions dashboards/PROD/PROD_STR_Cascadia.json

Large diffs are not rendered by default.

2,140 changes: 2,140 additions & 0 deletions dashboards/PROD/PROD_TEL_Cascadia.json

Large diffs are not rendered by default.

45 changes: 40 additions & 5 deletions dbc/cascadia.dbc
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,10 @@ BO_ 1025 MotorCommand: 5 DRD
SG_ EcoModeOn : 33|1@1+ (1,0) [0|1] "" MDI
SG_ SpeedUnits : 34|1@1+ (1,0) [0|1] "" STR

BO_ 1026 DRDMCUHealth: 4 DRD
SG_ DRDMCUSupplyVoltage : 0|16@1+ (1,0) [0|4000] "mV" Vector__XXX
SG_ DRDMCUTemperature : 16|16@1- (1,0) [-40|125] "degC" Vector__XXX

BO_ 1027 DRDDiagnostics: 8 DRD
SG_ RawADC1 : 0|16@1+ (1,0) [0|65535] "" Vector__XXX
SG_ RawADC2 : 16|16@1+ (1,0) [0|65535] "" Vector__XXX
Expand All @@ -479,6 +483,8 @@ BO_ 1027 DRDDiagnostics: 8 DRD
SG_ ADCMismatch : 35|1@1+ (1,0) [0|1] "" Vector__XXX
SG_ DRDWatchdogReset : 36|1@1+ (1,0) [0|1] "" Vector__XXX
SG_ MotorCommFault : 37|1@1+ (1,0) [0|1] "" Vector__XXX
SG_ DRDMCUOverTemp : 38|1@1+ (1,0) [0|1] "" Vector__XXX
SG_ DRDMCUUnderVoltage : 39|1@1+ (1,0) [0|1] "" Vector__XXX
SG_ DriveState : 40|8@1+ (1,0) [0|255] "" Vector__XXX
SG_ SpeedTimeout : 48|1@1+ (1,0) [0|1] "" Vector__XXX
SG_ DriveStateTimeout : 49|1@1+ (1,0) [0|1] "" Vector__XXX
Expand All @@ -498,10 +504,13 @@ BO_ 1281 MDIDiagnostics: 1 MDI
SG_ MDIWatchdogReset : 0|1@1+ (1,0) [0|1] "" Vector__XXX
SG_ MDIVoltageOverThreshold : 1|1@1+ (1,0) [0|1] "" Vector__XXX
SG_ MDIMotorOverTemp : 2|1@1+ (1,0) [0|1] "" Vector__XXX
SG_ MDIRTDFault : 3|1@1+ (1,0) [0|1] "" Vector__XXX
SG_ MDIRTDCommError : 4|1@1+ (1,0) [0|1] "" Vector__XXX

BO_ 1282 MDIMotorTemperature: 5 MDI
BO_ 1282 MDIMotorTemperature: 6 MDI
SG_ RTDReadSuccess : 0|1@1+ (1,0) [0|1] "" Vector__XXX
SG_ MotorTemperature : 8|32@1- (1,0) [-100|300] "degC" Vector__XXX
SG_ RTDFaultFlags : 40|8@1+ (1,0) [0|255] "" Vector__XXX

BO_ 1408 STRDRDControl: 8 STR
SG_ STRRegenEnabled : 0|1@1+ (1,0) [0|1] "" Vector__XXX
Expand All @@ -521,6 +530,14 @@ BO_ 1409 STRTimeSinceBootup: 4 STR
BO_ 1410 STRDiagnostics: 1 STR
SG_ STRWatchdogReset : 0|1@1+ (1,0) [0|1] "" Vector__XXX

BO_ 1425 STRMCUHealth: 4 STR
SG_ STRMCUVoltage : 0|16@1+ (1,0) [0|65535] "mV" Vector__XXX
SG_ STRMCUTemperature : 16|16@1- (1,0) [-40|125] "degC" Vector__XXX

BO_ 1426 STRFlags: 1 STR
SG_ STRMCUUnderVoltage : 0|1@1+ (1,0) [0|1] "" Vector__XXX
SG_ STRMCUOverTemp : 1|1@1+ (1,0) [0|1] "" Vector__XXX

BO_ 1696 MPPTInputMeasurementsA: 8 MPPT
SG_ InputVoltageA : 0|32@1- (1,0) [-3.4e+38|3.4e+38] "V" Vector__XXX
SG_ InputCurrentA : 32|32@1- (1,0) [-3.4e+38|3.4e+38] "A" Vector__XXX
Expand Down Expand Up @@ -758,6 +775,8 @@ BO_ 1873 TELDiagnostics: 1 TEL
SG_ IMUWriteFail : 2|1@1+ (1,0) [0|1] "" Vector__XXX
SG_ GPSReadFail : 3|1@1+ (1,0) [0|1] "" Vector__XXX
SG_ GPSWriteFail : 4|1@1+ (1,0) [0|1] "" Vector__XXX
SG_ MCUOvertemp : 5|1@1+ (1,0) [0|1] "" Vector__XXX
SG_ MCUUndervoltage : 6|1@1+ (1,0) [0|1] "" Vector__XXX

BO_ 1874 TELImuAG_X: 8 TEL
SG_ ImuAGXAccel : 0|32@1- (1,0) [-3.4e+38|3.4e+38] "m/s^2" Vector__XXX
Expand Down Expand Up @@ -812,8 +831,9 @@ BO_ 1883 TELGpsUtcTime: 6 TEL
BO_ 1891 CANBusLoad: 1 TEL
SG_ BusLoad : 0|8@1+ (1,0) [0|100] "%" Vector__XXX

BO_ 1892 CPULoad: 4 TEL
SG_ CPULoad : 0|32@1- (1,0) [-3.4e+38|3.4e+38] "" Vector__XXX
BO_ 1892 TELMCUHealth: 4 TEL
SG_ MCU_Voltage : 0|16@1+ (1,0) [0|65535] "mV" Vector__XXX
SG_ MCU_Temperature : 16|16@1- (1,0) [-40|125] "degC" Vector__XXX

BO_ 2290418213 Mitsuba_Frame0: 8 MC
SG_ BatteryVoltage : 0|10@1+ (0.5,0) [0|511.5] "V" DRD
Expand Down Expand Up @@ -931,6 +951,17 @@ CM_ BO_ 932 "Firmware branch ID";
CM_ BO_ 1025 "Motor command to MDI. Also sent immediately when the brake is pressed.";
CM_ SG_ 1027 SOC "SOC_MAX is 1.04 so values up to 104 are possible";
CM_ SG_ 1281 MDIMotorOverTemp "Set at 100 degC, cleared at 95 degC";
CM_ SG_ 1281 MDIVoltageOverThreshold "Not set by current MDI firmware (always 0)";
CM_ SG_ 1281 MDIRTDFault "1 = RTD fault latched: +1 per faulted read, -1 per clean read, sets at 5, clears at 0";
CM_ SG_ 1281 MDIRTDCommError "1 = SPI error, or MAX31865 missing/reset";
CM_ SG_ 1282 RTDReadSuccess "1 = valid read, 0 = fault/HAL error";
CM_ SG_ 1282 RTDFaultFlags "MAX31865 fault register: 0x80 = RTD high, 0x40 = RTD low, 0x04 = OV/UV, 0 = none";
CM_ SG_ 1026 DRDMCUSupplyVoltage "0 = read failed";
CM_ SG_ 1027 DRDMCUOverTemp "1 = fault: DRD MCU over temperature";
CM_ SG_ 1027 DRDMCUUnderVoltage "1 = fault: DRD MCU under voltage";
CM_ SG_ 1425 STRMCUVoltage "0 = read failed";
CM_ SG_ 1426 STRMCUUnderVoltage "1 = fault: STR MCU Vdd below 2400 mV";
CM_ SG_ 1426 STRMCUOverTemp "1 = fault: STR MCU above 105 degC";
CM_ BO_ 1408 "Steering inputs. Firmware sends 8 bytes; bytes 4-7 are 0.";
CM_ BO_ 1410 "Not sent by current STR firmware (kept for existing dashboards)";
CM_ BO_ 1704 "Command to MPPT A";
Expand All @@ -949,7 +980,7 @@ CM_ BO_ 1872 "HVC uses this as the TEL heartbeat";
CM_ BO_ 1880 "Only sent with a valid fix";
CM_ BO_ 1881 "Only sent with a valid fix";
CM_ BO_ 1883 "Only sent with a valid UTC date and time";
CM_ BO_ 1892 "Not sent by current TEL firmware";
CM_ BO_ 1892 "TEL MCU health: Vdd and die temperature, 10 Hz (firmware tel/app/diagnostics.c)";
CM_ BO_ 2290418213 "Sent in response to MitsubaDataRequest";
CM_ SG_ 2290418213 MotorRotatingSpeed "rpm x 0.106688 (0.283 m wheel radius). Raw value is rpm.";
CM_ SG_ 2290418213 PWMDuty "Only valid in PWM control mode";
Expand Down Expand Up @@ -1000,13 +1031,16 @@ BA_ "GenMsgCycleTime" BO_ 930 500;
BA_ "GenMsgCycleTime" BO_ 931 1000;
BA_ "GenMsgCycleTime" BO_ 932 1000;
BA_ "GenMsgCycleTime" BO_ 1025 25;
BA_ "GenMsgCycleTime" BO_ 1026 1000;
BA_ "GenMsgCycleTime" BO_ 1027 100;
BA_ "GenMsgCycleTime" BO_ 1028 1000;
BA_ "GenMsgCycleTime" BO_ 1280 1000;
BA_ "GenMsgCycleTime" BO_ 1281 1000;
BA_ "GenMsgCycleTime" BO_ 1282 1000;
BA_ "GenMsgCycleTime" BO_ 1408 100;
BA_ "GenMsgCycleTime" BO_ 1409 1000;
BA_ "GenMsgCycleTime" BO_ 1425 100;
BA_ "GenMsgCycleTime" BO_ 1426 100;
BA_ "GenMsgCycleTime" BO_ 1872 1000;
BA_ "GenMsgCycleTime" BO_ 1873 100;
BA_ "GenMsgCycleTime" BO_ 1874 100;
Expand All @@ -1020,6 +1054,7 @@ BA_ "GenMsgCycleTime" BO_ 1881 1000;
BA_ "GenMsgCycleTime" BO_ 1882 1000;
BA_ "GenMsgCycleTime" BO_ 1883 1000;
BA_ "GenMsgCycleTime" BO_ 1891 100;
BA_ "GenMsgCycleTime" BO_ 1892 100;
BA_ "VFrameFormat" BO_ 2290418213 1;
BA_ "GenMsgCycleTime" BO_ 2290418213 100;
BA_ "VFrameFormat" BO_ 2291466789 1;
Expand All @@ -1034,6 +1069,7 @@ VAL_ 1025 Direction 1 "Forward" 0 "Reverse";
VAL_ 1025 EcoModeOn 1 "Eco" 0 "Power";
VAL_ 1025 SpeedUnits 1 "KPH" 0 "MPH";
VAL_ 1027 DriveState 4 "REVERSE" 3 "PARK" 2 "CRUISE" 1 "FORWARD" 0 "INVALID";
VAL_ 1282 RTDFaultFlags 128 "RTD high" 64 "RTD low" 4 "OV/UV" 0 "None";
VAL_ 1882 GpsFixType 5 "TimeOnly" 4 "GnssDeadReckoning" 3 "Fix3D" 2 "Fix2D" 1 "DeadReckoning" 0 "NoFix";
VAL_ 2290418213 BatteryCurrentDirection 1 "Negative" 0 "Positive";
VAL_ 2291466789 PowerMode 1 "Power" 0 "Eco";
Expand Down Expand Up @@ -1122,4 +1158,3 @@ SIG_VALTYPE_ 1876 ImuAGZGyro : 1;
SIG_VALTYPE_ 1877 ImuMXMag : 1;
SIG_VALTYPE_ 1878 ImuMYMag : 1;
SIG_VALTYPE_ 1879 ImuMZMag : 1;
SIG_VALTYPE_ 1892 CPULoad : 1;
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/cascadia_dashboards/drd_normal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/cascadia_dashboards/mdi_normal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/cascadia_dashboards/mdi_overtemp.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/cascadia_dashboards/str_normal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/cascadia_dashboards/tel_gps_warning.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/cascadia_dashboards/tel_normal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
118 changes: 118 additions & 0 deletions tools/cascadia_sim/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Cascadia data simulator

Generates realistic Cascadia CAN data for the **TEL, MDI, DRD and STR** boards and writes it to your
local InfluxDB. Use it to look at the Cascadia Grafana dashboards without the car. It sends the same
frame IDs, rates and fault logic as `firmware_v4`. Each frame is encoded with `dbc/cascadia.dbc` and
decoded back, with enum signals stored as raw ints (the dashboards map them back to names). Points
are written with sunlink's layout: measurement = sender, field = signal, tags `car` and `class`.

A control panel lets you change what's happening while it runs: drive state, throttle, GPS fix,
temperatures, supply voltages, faults and so on. Presets jump straight to common cases.

## 1. Install

You need the normal sunlink setup: Docker running InfluxDB and Grafana, the `environment` venv, and a
`.env` file in the sunlink root. If you haven't done that yet, follow the main [README](../../README.md)
(`MacOS_setup.sh` on Mac, `setup.sh` on Linux).

Then, from the sunlink root:

```bash
source environment/bin/activate
pip install -r requirements.txt # Mac: requirements_MacOS.txt
```

The simulator only uses `cantools`, `influxdb-client` and `python-dotenv` from that list. The Tk
window (`--tk`) also needs a Python with Tk support. Most installs have it. If yours doesn't, use the
browser panel.

Check that:

- the containers are up: `docker compose up -d`. InfluxDB should be on `localhost:8086` and Grafana
on `localhost:3000`.
- `.env` contains `INFLUX_TOKEN` and `INFLUX_ORG`. The setup script writes both.
- the `CAN_prod` bucket exists. The setup script creates it.

The Cascadia dashboards (`dashboards/PROD/PROD_*_Cascadia.json`) are mounted into Grafana
automatically. If they don't appear, run `docker compose restart grafana`.

## 2. Run

Run every command from the sunlink root with the venv active.

```bash
python tools/cascadia_sim/cascadia_sim.py
```

This starts writing data and opens the control panel at <http://localhost:8090>. The panel has
scenario buttons, toggles and sliders for every input, a live readout, and links to the four
dashboards. Stop it with Ctrl+C.

Other ways to run it:

```bash
python tools/cascadia_sim/cascadia_sim.py --tk # same controls in a Tk window
python tools/cascadia_sim/cascadia_sim.py --list-scenarios # show the presets
python tools/cascadia_sim/cascadia_sim.py --scenario gps_lost --headless --duration 120 # no UI, 2 minutes
```

Then open a dashboard. Set the time range to the last 5 minutes and refresh to 1 s:

| Board | URL |
|---|---|
| TEL | <http://localhost:3000/d/cascadia-prod-tel> |
| MDI | <http://localhost:3000/d/cascadia-prod-mdi> |
| DRD | <http://localhost:3000/d/cascadia-prod-drd> |
| STR | <http://localhost:3000/d/cascadia-prod-str> |

### Options

| Flag | Default | What it does |
|---|---|---|
| `--scenario NAME` | `normal` | Preset to start in (see below) |
| `--headless` | off | No window or panel. Runs the scenario and prints how many frames were written |
| `--duration SECONDS` | forever | How long a headless run lasts |
| `--tk` | off | Tk window instead of the browser panel |
| `--port N` | `8090` | Port for the browser panel (bound to 127.0.0.1 only) |
| `--url URL` | `http://localhost:8086` | InfluxDB to write to |
| `--bucket NAME` | `CAN_prod` | Bucket to write to |
| `--dbc PATH` | `dbc/cascadia.dbc` | DBC used to encode and decode |
| `--allow-remote` | off | Allow writing to an InfluxDB that isn't on localhost |

### Scenarios

| Name | Situation |
|---|---|
| `normal` | Normal driving: 3D fix, everything in band |
| `parked` | Parked on the bench, no throttle |
| `cruise` | Cruise at 60 km/h |
| `gps_lost` | GPS lost (no fix, few satellites) |
| `motor_overheat` | Hard driving, motor temperature climbs past 100 °C |
| `rtd_failure` | Motor RTD open circuit |
| `drd_mcu_hot` | DRD MCU over temperature |
| `str_brownout` | STR supply sagging below 2400 mV |
| `tel_link_down` | TEL stops sending (radio/CAN down) |
| `drd_reset` | DRD watchdog reset |
| `pedal_mismatch` | Throttle sensors disagree |
| `timeouts` | DRD lost its cyclic inputs (BMS/MC silent) |
| `bus_overload` | CAN bus load 92 % |

## Safety

- **Local only by default.** The simulator refuses to write anywhere other than `localhost` unless you
pass `--allow-remote`. Don't point it at a shared or race InfluxDB.
- **Simulated points are tagged.** Every point it writes has the tag `source=cascadia_sim`.
**Reset everything to normal** in the panel restores normal inputs, clears latched faults, and
deletes only points with that tag. Real data imported into the same bucket is left alone. The
dashboards ignore the tag, so simulated and real data look the same on them.
- The `car` tag comes from `CAR_NAME` in `LINK_CONSTANTS.py`.

## Troubleshooting

| Problem | Fix |
|---|---|
| `ModuleNotFoundError: No module named 'cantools'` | The venv isn't active, or the requirements aren't installed (step 1) |
| `KeyError: 'INFLUX_TOKEN'` | `.env` is missing or incomplete. Re-run the setup script |
| `refusing to write simulated data to ...` | `--url` isn't localhost. Add `--allow-remote` only if you really mean it |
| Dashboards are empty | Check the time range is recent, the bucket is `CAN_prod`, and the panel's frame counter is going up |
| Port 8090 already in use | Pass `--port 8091` (or any free port) |
Loading
Loading