1use super::{
2 BuildError, Cpu, Description, EmptyToNone, Name, Peripheral, RegisterProperties, SvdError,
3 ValidateLevel,
4};
5
6#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
8pub enum Error {
9 #[error("Device must contain at least one peripheral")]
11 EmptyDevice,
12}
13
14#[cfg_attr(
16 feature = "serde",
17 derive(serde::Deserialize, serde::Serialize),
18 serde(rename_all = "camelCase")
19)]
20#[derive(Clone, Debug, PartialEq)]
21#[non_exhaustive]
22pub struct Device {
23 #[cfg_attr(
25 feature = "serde",
26 serde(default, skip_serializing_if = "Option::is_none")
27 )]
28 pub vendor: Option<String>,
29
30 #[cfg_attr(
32 feature = "serde",
33 serde(default, skip_serializing_if = "Option::is_none", rename = "vendorID")
34 )]
35 pub vendor_id: Option<String>,
36
37 pub name: String,
39
40 #[cfg_attr(
42 feature = "serde",
43 serde(default, skip_serializing_if = "Option::is_none")
44 )]
45 pub series: Option<String>,
46
47 pub version: String,
49
50 pub description: String,
52
53 #[cfg_attr(
55 feature = "serde",
56 serde(default, skip_serializing_if = "Option::is_none")
57 )]
58 pub license_text: Option<String>,
59
60 #[cfg_attr(
62 feature = "serde",
63 serde(default, skip_serializing_if = "Option::is_none")
64 )]
65 pub cpu: Option<Cpu>,
66
67 #[cfg_attr(
69 feature = "serde",
70 serde(default, skip_serializing_if = "Option::is_none")
71 )]
72 pub header_system_filename: Option<String>,
73
74 #[cfg_attr(
76 feature = "serde",
77 serde(default, skip_serializing_if = "Option::is_none")
78 )]
79 pub header_definitions_prefix: Option<String>,
80
81 pub address_unit_bits: u32,
83
84 pub width: u32,
86
87 #[cfg_attr(feature = "serde", serde(flatten))]
89 pub default_register_properties: RegisterProperties,
90
91 pub peripherals: Vec<Peripheral>,
93
94 #[cfg_attr(feature = "serde", serde(skip, default = "default_xmlns_xs"))]
96 pub xmlns_xs: String,
97
98 #[cfg_attr(
100 feature = "serde",
101 serde(skip, default = "default_no_namespace_schema_location")
102 )]
103 pub no_namespace_schema_location: String,
104
105 #[cfg_attr(feature = "serde", serde(skip, default = "default_schema_version"))]
107 pub schema_version: String,
108}
109
110fn default_xmlns_xs() -> String {
111 "http://www.w3.org/2001/XMLSchema-instance".into()
112}
113fn default_no_namespace_schema_location() -> String {
114 format!(
115 "CMSIS-SVD_Schema_{}.xsd",
116 default_schema_version().replace('.', "_")
117 )
118}
119fn default_schema_version() -> String {
120 "1.1".into()
121}
122
123#[derive(Clone, Debug, Default)]
125pub struct DeviceBuilder {
126 vendor: Option<String>,
127 vendor_id: Option<String>,
128 name: Option<String>,
129 series: Option<String>,
130 version: Option<String>,
131 description: Option<String>,
132 license_text: Option<String>,
133 cpu: Option<Cpu>,
134 header_system_filename: Option<String>,
135 header_definitions_prefix: Option<String>,
136 address_unit_bits: Option<u32>,
137 width: Option<u32>,
138 default_register_properties: RegisterProperties,
139 peripherals: Option<Vec<Peripheral>>,
140 xmlns_xs: Option<String>,
141 no_namespace_schema_location: Option<String>,
142 schema_version: Option<String>,
143}
144
145impl From<Device> for DeviceBuilder {
146 fn from(d: Device) -> Self {
147 Self {
148 vendor: d.vendor,
149 vendor_id: d.vendor_id,
150 name: Some(d.name),
151 series: d.series,
152 version: Some(d.version),
153 description: Some(d.description),
154 license_text: d.license_text,
155 cpu: d.cpu,
156 header_system_filename: d.header_system_filename,
157 header_definitions_prefix: d.header_definitions_prefix,
158 address_unit_bits: Some(d.address_unit_bits),
159 width: Some(d.width),
160 default_register_properties: d.default_register_properties,
161 peripherals: Some(d.peripherals),
162 xmlns_xs: Some(d.xmlns_xs),
163 no_namespace_schema_location: Some(d.no_namespace_schema_location),
164 schema_version: Some(d.schema_version),
165 }
166 }
167}
168
169impl DeviceBuilder {
170 pub fn vendor(mut self, value: Option<String>) -> Self {
172 self.vendor = value;
173 self
174 }
175 pub fn vendor_id(mut self, value: Option<String>) -> Self {
177 self.vendor_id = value;
178 self
179 }
180 pub fn name(mut self, value: String) -> Self {
182 self.name = Some(value);
183 self
184 }
185 pub fn series(mut self, value: Option<String>) -> Self {
187 self.series = value;
188 self
189 }
190 pub fn version(mut self, value: String) -> Self {
192 self.version = Some(value);
193 self
194 }
195 pub fn description(mut self, value: String) -> Self {
197 self.description = Some(value);
198 self
199 }
200 pub fn license_text(mut self, value: Option<String>) -> Self {
202 self.license_text = value;
203 self
204 }
205 pub fn cpu(mut self, value: Option<Cpu>) -> Self {
207 self.cpu = value;
208 self
209 }
210 pub fn header_system_filename(mut self, value: Option<String>) -> Self {
212 self.header_system_filename = value;
213 self
214 }
215 pub fn header_definitions_prefix(mut self, value: Option<String>) -> Self {
217 self.header_definitions_prefix = value;
218 self
219 }
220 pub fn address_unit_bits(mut self, value: u32) -> Self {
222 self.address_unit_bits = Some(value);
223 self
224 }
225 pub fn width(mut self, value: u32) -> Self {
227 self.width = Some(value);
228 self
229 }
230 pub fn default_register_properties(mut self, value: RegisterProperties) -> Self {
232 self.default_register_properties = value;
233 self
234 }
235 pub fn peripherals(mut self, value: Vec<Peripheral>) -> Self {
237 self.peripherals = Some(value);
238 self
239 }
240 pub fn xmlns_xs(mut self, value: String) -> Self {
242 self.xmlns_xs = Some(value);
243 self
244 }
245 pub fn no_namespace_schema_location(mut self, value: String) -> Self {
247 self.no_namespace_schema_location = Some(value);
248 self
249 }
250 pub fn schema_version(mut self, value: String) -> Self {
252 self.schema_version = Some(value);
253 self
254 }
255 pub fn build(self, lvl: ValidateLevel) -> Result<Device, SvdError> {
257 let schema_version = self.schema_version.unwrap_or_else(default_schema_version);
258 let device = Device {
259 vendor: self.vendor,
260 vendor_id: self.vendor_id,
261 name: self
262 .name
263 .ok_or_else(|| BuildError::Uninitialized("name".to_string()))?,
264 series: self.series,
265 version: self
266 .version
267 .or_else(|| {
268 if !lvl.is_strict() {
269 Some("1.0".into())
270 } else {
271 None
272 }
273 })
274 .ok_or_else(|| BuildError::Uninitialized("version".to_string()))?,
275 description: self
276 .description
277 .or_else(|| {
278 if !lvl.is_strict() {
279 Some("".into())
280 } else {
281 None
282 }
283 })
284 .ok_or_else(|| BuildError::Uninitialized("description".to_string()))?,
285 license_text: self.license_text,
286 cpu: self.cpu,
287 header_system_filename: self.header_system_filename,
288 header_definitions_prefix: self.header_definitions_prefix,
289 address_unit_bits: self
290 .address_unit_bits
291 .or_else(|| if !lvl.is_strict() { Some(8) } else { None })
292 .ok_or_else(|| BuildError::Uninitialized("addressUnitBits".to_string()))?,
293 width: self
294 .width
295 .or_else(|| if !lvl.is_strict() { Some(32) } else { None })
296 .ok_or_else(|| BuildError::Uninitialized("width".to_string()))?,
297 default_register_properties: self.default_register_properties.build(lvl)?,
298 peripherals: self
299 .peripherals
300 .ok_or_else(|| BuildError::Uninitialized("peripherals".to_string()))?,
301 xmlns_xs: self.xmlns_xs.unwrap_or_else(default_xmlns_xs),
302 no_namespace_schema_location: self
303 .no_namespace_schema_location
304 .unwrap_or_else(default_no_namespace_schema_location),
305 schema_version,
306 };
307 device.validate(lvl)?;
308 Ok(device)
309 }
310}
311
312impl Device {
313 pub fn builder() -> DeviceBuilder {
315 DeviceBuilder::default()
316 }
317 pub fn modify_from(
319 &mut self,
320 builder: DeviceBuilder,
321 lvl: ValidateLevel,
322 ) -> Result<(), SvdError> {
323 if builder.vendor.is_some() {
324 self.vendor = builder.vendor.empty_to_none();
325 }
326 if builder.vendor_id.is_some() {
327 self.vendor_id = builder.vendor_id.empty_to_none();
328 }
329 if let Some(name) = builder.name {
330 self.name = name;
331 }
332 if builder.series.is_some() {
333 self.series = builder.series.empty_to_none();
334 }
335 if let Some(version) = builder.version {
336 self.version = version;
337 }
338 if let Some(description) = builder.description {
339 self.description = description;
340 }
341 if builder.license_text.is_some() {
342 self.license_text = builder.license_text.empty_to_none();
343 }
344 if builder.cpu.is_some() {
345 self.cpu = builder.cpu;
346 }
347 if builder.header_system_filename.is_some() {
348 self.header_system_filename = builder.header_system_filename.empty_to_none();
349 }
350 if builder.header_definitions_prefix.is_some() {
351 self.header_definitions_prefix = builder.header_definitions_prefix.empty_to_none();
352 }
353 if let Some(address_unit_bits) = builder.address_unit_bits {
354 self.address_unit_bits = address_unit_bits;
355 }
356 if let Some(width) = builder.width {
357 self.width = width;
358 }
359 self.default_register_properties
360 .modify_from(builder.default_register_properties, lvl)?;
361 if let Some(peripherals) = builder.peripherals {
362 self.peripherals = peripherals;
363 }
364 if let Some(xmlns_xs) = builder.xmlns_xs {
365 self.xmlns_xs = xmlns_xs;
366 }
367 if let Some(no_namespace_schema_location) = builder.no_namespace_schema_location {
368 self.no_namespace_schema_location = no_namespace_schema_location;
369 }
370 if let Some(schema_version) = builder.schema_version {
371 self.schema_version = schema_version;
372 }
373 self.validate(lvl)
374 }
375
376 pub fn validate(&self, lvl: ValidateLevel) -> Result<(), SvdError> {
378 if !lvl.is_disabled() {
379 if self.peripherals.is_empty() {
381 return Err(Error::EmptyDevice.into());
382 }
383 }
384 Ok(())
385 }
386 pub fn validate_all(&self, lvl: ValidateLevel) -> Result<(), SvdError> {
388 if let Some(cpu) = self.cpu.as_ref() {
389 cpu.validate(lvl)?;
390 }
391 self.default_register_properties.validate(lvl)?;
392 for p in &self.peripherals {
393 p.validate_all(lvl)?;
394 }
395 self.validate(lvl)
396 }
397
398 pub fn get_peripheral(&self, name: &str) -> Option<&Peripheral> {
400 self.peripherals.iter().find(|f| f.name == name)
401 }
402
403 pub fn get_mut_peripheral(&mut self, name: &str) -> Option<&mut Peripheral> {
405 self.peripherals.iter_mut().find(|f| f.name == name)
406 }
407}
408
409impl Name for Device {
410 fn name(&self) -> &str {
411 &self.name
412 }
413}
414
415impl Description for Device {
416 fn description(&self) -> Option<&str> {
417 Some(&self.description)
418 }
419}