This repository was archived by the owner on Aug 6, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Simple CAN based HIL #83
Merged
Merged
Changes from all commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
8e5951b
sort of deciding on a test format
LelsersLasers 958302a
schema for tests
LelsersLasers f62580a
serde to read configs
LelsersLasers 8baf9da
able to list all presets and tests (untested)
LelsersLasers ac5c070
Fix config loading
LelsersLasers d31ef42
Wiring HIL widget + trying to think about UI state
LelsersLasers 637a792
System to kind of load a test
LelsersLasers 254ff29
start from preset
LelsersLasers da5278e
Basic UI started for in progress tests
LelsersLasers e41a043
Trying to work on UI
LelsersLasers 2ddd221
improve in progress UI
LelsersLasers e2f056a
Test summary UI
LelsersLasers d0f096e
Breaking into helper functions
LelsersLasers bcddfa7
Thinking about HIL state machine
LelsersLasers 21684ca
update heartbeat tests to be accurate
LelsersLasers b34c775
sorting tests by basename, presets by name
LelsersLasers bbfca61
Actually running expects + can stop a test midway
LelsersLasers 28a7d11
fmt :skull:
LelsersLasers 1bfce2d
remove unused import
LelsersLasers b13c261
Clear start errors on new start attempt
LelsersLasers b94819e
Clear start error on reload
LelsersLasers 78a468d
actually displaying start error
LelsersLasers 3f28ad7
total_cmp so NaN's don't nuke?
LelsersLasers c232556
Clean loading + filter for .json
LelsersLasers d6762e3
Fix typos
LelsersLasers 9cd1584
typos
LelsersLasers ee515d8
Fix failed rebase
LelsersLasers 4e8b04b
fmt
LelsersLasers 1955e4f
typo fix
LelsersLasers File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| { | ||
| "All Heartbeats": [ "heartbeats_crit", "heartbeats_non_crit" ] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| { | ||
| "$schema": "https://json-schema.org/draft/2020-12/schema", | ||
| "type": "object", | ||
|
|
||
| "required": ["name", "description", "expect"], | ||
|
|
||
| "properties": { | ||
| "$schema": { | ||
| "type": "string" | ||
| }, | ||
|
|
||
| "name": { | ||
| "type": "string" | ||
| }, | ||
|
|
||
| "description": { | ||
| "type": "string" | ||
| }, | ||
|
|
||
| "tx": { | ||
| "type": "array", | ||
| "items": { | ||
| "type": "object", | ||
| "required": ["timestamp", "msg_name", "signals"], | ||
|
|
||
| "properties": { | ||
| "timestamp": { | ||
| "type": "number" | ||
| }, | ||
|
|
||
| "msg_name": { | ||
| "type": "string" | ||
| }, | ||
|
|
||
| "signals": { | ||
| "type": "object", | ||
| "additionalProperties": { | ||
| "type": "number" | ||
| } | ||
| } | ||
| }, | ||
|
|
||
| "additionalProperties": false | ||
| } | ||
| }, | ||
|
|
||
| "expect": { | ||
| "type": "array", | ||
| "items": { | ||
| "type": "object", | ||
| "required": ["window", "msg_name"], | ||
|
|
||
| "properties": { | ||
| "window": { | ||
| "type": "array", | ||
| "items": { | ||
| "type": "number" | ||
| }, | ||
| "minItems": 2, | ||
| "maxItems": 2 | ||
| }, | ||
|
|
||
| "msg_name": { | ||
| "type": "string" | ||
| }, | ||
|
|
||
| "signals": { | ||
| "type": "object", | ||
| "additionalProperties": { | ||
| "type": "array", | ||
| "items": { | ||
| "type": "number" | ||
| }, | ||
| "minItems": 2, | ||
| "maxItems": 2 | ||
| } | ||
| } | ||
| }, | ||
|
|
||
| "additionalProperties": false | ||
| } | ||
| } | ||
| }, | ||
|
|
||
| "additionalProperties": false | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| { | ||
| "$schema": "../schema.json", | ||
|
|
||
| "name": "Critical Heartbeats", | ||
| "description": "Check that we receive a heartbeat (version hash) from every drive critical board", | ||
|
|
||
| "expect": [ | ||
| { | ||
| "window": [0, 10000], | ||
| "msg_name": "abox_version" | ||
| }, | ||
| { | ||
| "window": [0, 10000], | ||
| "msg_name": "dash_version" | ||
| }, | ||
| { | ||
| "window": [0, 10000], | ||
| "msg_name": "main_version" | ||
| }, | ||
| { | ||
| "window": [0, 10000], | ||
| "msg_name": "pdu_version" | ||
| } | ||
| ] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| { | ||
| "$schema": "../schema.json", | ||
|
|
||
| "name": "Non-Critical Heartbeats", | ||
| "description": "Check that we receive a heartbeat (version hash) from non-critical boards", | ||
|
|
||
| "expect": [ | ||
| { | ||
| "window": [0, 10000], | ||
| "msg_name": "front_driveline_version" | ||
| }, | ||
| { | ||
| "window": [0, 10000], | ||
| "msg_name": "rear_driveline_version" | ||
| } | ||
| ] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| { | ||
| "$schema": "../schema.json", | ||
|
|
||
| "name": "Pack sanity check", | ||
| "description": "Verify thermistor response", | ||
|
|
||
| "tx": [ | ||
| { | ||
| "timestamp": 15, | ||
| "msg_name": "pack_stats", | ||
| "signals": { | ||
| "pack_voltage": 540.0, | ||
| "pack_current": 10.0, | ||
| "max_temp": 35.0 | ||
| } | ||
| } | ||
| ], | ||
| "expect": [ | ||
| { | ||
| "window": [15, 20], | ||
| "msg_name": "thermistor_telemetry", | ||
| "signals": { | ||
| "temperature": [30.0, 40.0] | ||
| } | ||
| } | ||
| ] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,159 @@ | ||
| // Read HIL config files (preset and tests) | ||
|
|
||
| use serde::{Deserialize, Serialize}; | ||
| use std::collections::HashMap; | ||
|
|
||
| pub const PRESETS_FILE: &str = "hil_config/presets.json"; | ||
| pub const TESTS_FOLDER: &str = "hil_config/tests/"; | ||
|
|
||
| #[derive(Debug, Clone, Serialize, Deserialize)] | ||
| #[serde(transparent)] | ||
| pub struct PresetsFile(pub HashMap<String, Vec<String>>); | ||
|
|
||
| #[derive(Debug, Clone, Serialize, Deserialize)] | ||
| pub struct TestFile { | ||
| pub name: String, | ||
| pub description: String, | ||
|
|
||
| #[serde(default)] | ||
| pub tx: Vec<TxMessage>, | ||
|
|
||
| pub expect: Vec<Expectation>, | ||
| } | ||
|
|
||
| #[derive(Debug, Clone, Serialize, Deserialize)] | ||
| pub struct TxMessage { | ||
| pub timestamp: f64, | ||
| pub msg_name: String, | ||
|
|
||
| pub signals: HashMap<String, f64>, | ||
| } | ||
|
|
||
| #[derive(Debug, Clone, Serialize, Deserialize)] | ||
| pub struct Expectation { | ||
| pub window: [f64; 2], | ||
|
|
||
| pub msg_name: String, | ||
|
|
||
| #[serde(default)] | ||
| pub signals: HashMap<String, [f64; 2]>, | ||
| } | ||
|
|
||
| #[derive(Clone)] | ||
| pub struct PresetInfo { | ||
| pub name: String, | ||
| // base names | ||
| pub tests: Vec<String>, | ||
| } | ||
|
|
||
| #[derive(Clone)] | ||
| pub struct TestInfo { | ||
| pub basename: String, | ||
| pub name: String, | ||
| pub description: String, | ||
| } | ||
|
|
||
| pub fn list_available_tests() -> (Vec<PresetInfo>, Vec<TestInfo>, Vec<String>) { | ||
| let mut errors = Vec::new(); | ||
|
|
||
| // Load individual tests | ||
| let mut individual_tests = Vec::new(); | ||
| if let Ok(entries) = std::fs::read_dir(TESTS_FOLDER) { | ||
| for entry in entries.flatten() { | ||
| let path = entry.path(); | ||
| if !path.is_file() || path.extension().and_then(|e| e.to_str()) != Some("json") { | ||
| continue; | ||
| } | ||
|
|
||
| let basename = match path.file_stem().and_then(|s| s.to_str()) { | ||
| Some(stem) if !stem.is_empty() => stem.to_string(), | ||
| _ => { | ||
| errors.push(format!( | ||
| "Failed to determine test basename for file: {:?}", | ||
| path | ||
| )); | ||
| continue; | ||
| } | ||
| }; | ||
|
|
||
| let content = match std::fs::read_to_string(&path) { | ||
| Ok(c) => c, | ||
| Err(_) => { | ||
| errors.push(format!("Failed to read test file: {:?}", path)); | ||
| continue; | ||
| } | ||
| }; | ||
|
|
||
| match serde_json::from_str::<TestFile>(&content) { | ||
| Ok(test_data) => individual_tests.push(TestInfo { | ||
| basename, | ||
| name: test_data.name, | ||
| description: test_data.description, | ||
| }), | ||
| Err(_) => errors.push(format!("Failed to parse test file: {:?}", path)), | ||
| }; | ||
| } | ||
| } else { | ||
| errors.push(format!("Failed to read tests directory: {}", TESTS_FOLDER)); | ||
| } | ||
| individual_tests.sort_by(|a, b| a.basename.to_lowercase().cmp(&b.basename.to_lowercase())); | ||
|
|
||
| // Load presets | ||
| let mut presets = Vec::new(); | ||
| if let Ok(presets_file) = std::fs::read_to_string(PRESETS_FILE) { | ||
| if let Ok(presets_data) = serde_json::from_str::<PresetsFile>(&presets_file) { | ||
| for (preset_name, subtests) in presets_data.0 { | ||
| if subtests.is_empty() { | ||
| errors.push(format!("Preset '{}' has no subtests defined", preset_name)); | ||
| continue; | ||
| } | ||
|
|
||
| if subtests.iter().any(|s| s.trim().is_empty()) { | ||
| errors.push(format!( | ||
| "Preset '{}' contains empty subtest names", | ||
| preset_name | ||
| )); | ||
| continue; | ||
| } | ||
|
|
||
| if subtests | ||
| .iter() | ||
| .any(|s| individual_tests.iter().all(|t| t.basename != *s)) | ||
| { | ||
| errors.push(format!( | ||
| "Preset '{}' contains subtests that do not exist: {:?}", | ||
| preset_name, | ||
| subtests | ||
| .iter() | ||
| .filter(|s| individual_tests.iter().all(|t| t.basename != **s)) | ||
| .collect::<Vec<_>>() | ||
| )); | ||
| continue; | ||
| } | ||
|
|
||
| presets.push(PresetInfo { | ||
| name: preset_name, | ||
| tests: subtests, | ||
| }); | ||
| } | ||
| } else { | ||
| errors.push(format!("Failed to parse presets file: {}", PRESETS_FILE)); | ||
| } | ||
| } else { | ||
| errors.push(format!("Failed to read presets file: {}", PRESETS_FILE)); | ||
| } | ||
| presets.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase())); | ||
|
|
||
| (presets, individual_tests, errors) | ||
| } | ||
|
|
||
| pub fn load_test_from_file(basename: &str) -> Result<TestFile, String> { | ||
| let path = format!("{}{}.json", TESTS_FOLDER, basename); | ||
| match std::fs::read_to_string(&path) { | ||
| Ok(content) => match serde_json::from_str::<TestFile>(&content) { | ||
| Ok(test_data) => Ok(test_data), | ||
| Err(_) => Err(format!("Failed to parse test file: {}", path)), | ||
| }, | ||
| Err(_) => Err(format!("Failed to read test file: {}", path)), | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| pub mod config; | ||
| pub mod run; |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.