1use crate::config::error::ConfigError;
2use serde::Deserialize;
3use std::collections::BTreeMap;
4
5#[derive(Debug, Clone, Deserialize, Default)]
6pub struct DefaultsConfig {
7 pub json: Option<bool>,
8 pub speed: Option<f64>,
9 pub load: Option<LoadDefaults>,
10}
11
12#[derive(Debug, Clone, Deserialize, Default)]
13pub struct LoadDefaults {
14 pub lib: Option<String>,
15 #[serde(default)]
16 pub flash: Vec<FlashBlockDef>,
17}
18
19#[derive(Debug, Clone, Deserialize, Default)]
20pub struct FileConfig {
21 pub defaults: Option<DefaultsConfig>,
22 #[serde(default)]
23 pub device: BTreeMap<String, DeviceDef>,
24 #[serde(default)]
25 pub recipe: BTreeMap<String, RecipeDef>,
26 #[serde(default)]
27 pub env: BTreeMap<String, EnvDef>,
28}
29
30#[derive(Debug, Clone, Deserialize)]
31pub struct DeviceDef {
32 pub lib: String,
33 #[serde(default)]
34 pub flash: Vec<FlashBlockDef>,
35}
36
37#[derive(Debug, Clone, Deserialize)]
38pub struct RecipeDef {
39 pub description: Option<String>,
40 #[serde(default)]
41 pub env: Vec<String>,
42 #[serde(default)]
43 pub instances: Vec<String>,
44 pub instance: Option<String>,
45 pub steps: Vec<RecipeStep>,
46}
47
48#[derive(Debug, Clone, Deserialize)]
49#[serde(untagged)]
50pub enum PrintSpec {
51 All(String),
52 Signals(Vec<String>),
53}
54
55#[derive(Debug, Clone, Deserialize)]
56pub struct ForSpec {
57 pub signal: String,
58 pub from: f64,
59 pub to: f64,
60 pub by: f64,
61 pub each: Vec<RecipeStep>,
62}
63
64#[derive(Debug, Clone, Deserialize)]
65#[serde(untagged)]
66pub enum StepSpec {
67 Duration(String),
68 Detailed {
69 duration: String,
70 instance: Option<String>,
71 },
72}
73
74#[derive(Debug, Clone, Deserialize)]
75pub struct AssertSpec {
76 pub signal: String,
77 pub instance: Option<String>,
78 pub eq: Option<toml::Value>,
79 pub gt: Option<f64>,
80 pub lt: Option<f64>,
81 pub gte: Option<f64>,
82 pub lte: Option<f64>,
83 pub approx: Option<f64>,
84 pub tolerance: Option<f64>,
85}
86
87#[derive(Debug, Clone, Deserialize)]
88pub struct EnvDef {
89 #[serde(default)]
90 pub instances: Vec<EnvInstance>,
91 #[serde(default)]
92 pub can: BTreeMap<String, EnvCanBus>,
93 #[serde(default)]
94 pub shared: BTreeMap<String, EnvSharedChannel>,
95}
96
97#[derive(Debug, Clone, Deserialize)]
98#[serde(deny_unknown_fields)]
99pub struct EnvInstance {
100 pub name: String,
101 pub lib: Option<String>,
102 pub device: Option<String>,
103}
104
105#[derive(Debug, Clone, Deserialize)]
106#[serde(deny_unknown_fields)]
107pub struct FlashFileBlockDef {
108 pub file: String,
109 pub format: Option<String>,
110 pub base: Option<String>,
111}
112
113#[derive(Debug, Clone, Deserialize)]
114#[serde(untagged)]
115pub enum FlashBlockDef {
116 File(FlashFileBlockDef),
117 InlineU32 { u32: u32, addr: String },
118 InlineI32 { i32: i32, addr: String },
119 InlineF32 { f32: f32, addr: String },
120 InlineBool { bool: bool, addr: String },
121}
122
123#[derive(Debug, Clone, Deserialize)]
124pub struct EnvCanBus {
125 #[serde(default)]
126 pub members: Vec<String>,
127 pub vcan: String,
128 pub dbc: Option<String>,
129}
130
131#[derive(Debug, Clone, Deserialize)]
132pub struct EnvSharedChannel {
133 #[serde(default)]
134 pub members: Vec<String>,
135 pub writer: String,
136}
137
138#[derive(Debug, Clone, Deserialize)]
139#[serde(deny_unknown_fields)]
140pub struct ResetSpec {}
141
142#[derive(Debug, Clone, Deserialize)]
143#[serde(untagged)]
144pub enum RecipeStep {
145 Set {
146 set: BTreeMap<String, toml::Value>,
147 instance: Option<String>,
148 },
149 Step {
150 step: StepSpec,
151 instance: Option<String>,
152 },
153 Print {
154 print: PrintSpec,
155 instance: Option<String>,
156 },
157 Speed {
158 speed: f64,
159 instance: Option<String>,
160 },
161 Reset {
162 reset: ResetSpec,
163 instance: Option<String>,
164 },
165 Sleep {
166 sleep: u64,
167 },
168 For {
169 r#for: ForSpec,
170 instance: Option<String>,
171 },
172 Assert {
173 assert: AssertSpec,
174 },
175}
176
177pub fn parse_config(content: &str) -> Result<FileConfig, ConfigError> {
178 toml::from_str(content).map_err(|e| ConfigError::Parse(e.to_string()))
179}
180
181pub fn toml_value_to_cli_string(value: &toml::Value) -> Result<String, ConfigError> {
182 let rendered = match value {
183 toml::Value::String(v) => v.clone(),
184 toml::Value::Integer(v) => v.to_string(),
185 toml::Value::Float(v) => v.to_string(),
186 toml::Value::Boolean(v) => v.to_string(),
187 _ => {
188 return Err(ConfigError::InvalidRecipeStep(
189 "unsupported set value type".to_string(),
190 ));
191 }
192 };
193 Ok(rendered)
194}