1use serde::{Deserialize, Serialize};
9use std::collections::BTreeMap;
10
11#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
14pub struct BoardModel {
15 #[serde(default)]
18 pub schema_version: Option<u32>,
19
20 #[serde(default)]
22 pub som: Option<Som>,
23
24 #[serde(default)]
26 pub carrier: Option<Carrier>,
27
28 #[serde(default)]
30 pub os: Option<String>,
31
32 #[serde(default)]
34 pub preset: Option<String>,
35
36 #[serde(default)]
38 pub cores: Option<BTreeMap<String, CoreEntry>>,
39
40 #[serde(default)]
42 pub ipc: Option<Vec<IpcCarveOut>>,
43
44 #[serde(default)]
46 pub inference: Option<Inference>,
47
48 #[serde(default)]
50 pub libraries: Option<Vec<String>>,
51
52 #[serde(default)]
54 pub iot: Option<Iot>,
55
56 #[serde(default)]
58 pub diagnostics: Option<Diagnostics>,
59
60 #[serde(default)]
62 pub populated: Option<BTreeMap<String, bool>>,
63
64 #[serde(default)]
66 pub chips: Option<Vec<String>>,
67
68 #[serde(default)]
70 pub e1m_routes: Option<BTreeMap<String, serde_yaml::Value>>,
71}
72
73#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
75pub struct Som {
76 #[serde(default)]
78 pub sku: Option<String>,
79}
80
81#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
83pub struct Carrier {
84 #[serde(default)]
86 pub name: Option<String>,
87
88 #[serde(default)]
90 pub populated: Option<BTreeMap<String, bool>>,
91}
92
93#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
95pub struct CoreEntry {
96 #[serde(default)]
98 pub os: Option<String>,
99
100 #[serde(default)]
102 pub app: Option<String>,
103
104 #[serde(default)]
106 pub image: Option<String>,
107
108 #[serde(default)]
110 pub peripherals: Option<Vec<String>>,
111
112 #[serde(default)]
114 pub libraries: Option<Vec<String>>,
115
116 #[serde(default)]
118 pub inference: Option<Inference>,
119
120 #[serde(default)]
122 pub iot: Option<Iot>,
123}
124
125#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
127pub struct IpcCarveOut {
128 pub name: String,
130 pub endpoints: Vec<String>,
132 pub size_kib: u32,
134}
135
136#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
138pub struct Inference {
139 #[serde(default)]
141 pub backend: Option<String>,
142
143 #[serde(default)]
145 pub default_arena_kib: Option<u32>,
146}
147
148impl Inference {
149 pub fn is_empty(&self) -> bool {
151 self.backend.as_deref().unwrap_or_default().is_empty() && self.default_arena_kib.is_none()
152 }
153}
154
155#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
157pub struct Iot {
158 #[serde(default)]
160 pub wifi: Option<bool>,
161
162 #[serde(default)]
164 pub mqtt: Option<bool>,
165
166 #[serde(default)]
168 pub ble: Option<bool>,
169
170 #[serde(default)]
172 pub tls: Option<bool>,
173}
174
175impl Iot {
176 pub fn any_enabled(&self) -> bool {
178 matches!(self.wifi, Some(true))
179 || matches!(self.mqtt, Some(true))
180 || matches!(self.ble, Some(true))
181 || matches!(self.tls, Some(true))
182 }
183}
184
185#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
187pub struct Diagnostics {
188 #[serde(default)]
190 pub last_error: Option<bool>,
191
192 #[serde(default)]
194 pub log_level: Option<String>,
195}
196
197impl BoardModel {
198 pub fn effective_schema_version(&self) -> u32 {
200 self.schema_version.unwrap_or(1)
201 }
202}
203
204pub fn normalize_board_model(mut model: BoardModel) -> BoardModel {
207 if model.effective_schema_version() < 2 {
208 if model.libraries.as_ref().is_some_and(Vec::is_empty) {
209 model.libraries = None;
210 }
211
212 if model.iot.as_ref().is_some_and(|iot| !iot.any_enabled()) {
213 model.iot = None;
214 }
215
216 if model.inference.as_ref().is_some_and(Inference::is_empty) {
217 model.inference = None;
218 }
219
220 if let Some(carrier) = &mut model.carrier {
221 if carrier.populated.as_ref().is_some_and(BTreeMap::is_empty) {
222 carrier.populated = None;
223 }
224 }
225 }
226
227 if model.effective_schema_version() >= 2 {
228 model.os = None;
229 }
230
231 model
232}