Skip to main content

cmsis_pdsc_parser/
family.rs

1//! Contains the types required to represent a [PDSC Family](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html) element
2
3use crate::debug_access::{self, Statement};
4use log::{error, trace, warn};
5use roxmltree::Node;
6use serde::{Deserialize, Serialize};
7use serde_roxmltree::RawNode;
8use std::{collections::HashMap, fmt::Debug};
9
10/// Deserializes a `u32` from a decimal or `0x`-prefixed hex string.
11fn de_uint<'de, D>(d: D) -> Result<u32, D::Error>
12where
13    D: serde::Deserializer<'de>,
14{
15    let s = String::deserialize(d)?;
16    let trimmed = s.trim();
17    trimmed
18        .strip_prefix("0x")
19        .or_else(|| trimmed.strip_prefix("0X"))
20        .map_or_else(
21            || trimmed.parse::<u32>().map_err(serde::de::Error::custom),
22            |hex| u32::from_str_radix(hex, 16).map_err(serde::de::Error::custom),
23        )
24}
25
26/// Deserializes an `Option<u32>` from a decimal or `0x`-prefixed hex string.
27/// Only called when the field is present; absent fields use `default` (None).
28fn de_opt_uint<'de, D>(d: D) -> Result<Option<u32>, D::Error>
29where
30    D: serde::Deserializer<'de>,
31{
32    de_uint(d).map(Some)
33}
34
35/// Deserializes an `Option<bool>` from an xs:boolean string ("true", "false", "1", "0").
36/// Only called when the field is present; absent fields use `default` (None).
37fn de_opt_bool<'de, D>(d: D) -> Result<Option<bool>, D::Error>
38where
39    D: serde::Deserializer<'de>,
40{
41    let s = String::deserialize(d)?;
42    match s.as_str() {
43        "true" | "1" => Ok(Some(true)),
44        "false" | "0" => Ok(Some(false)),
45        other => Err(serde::de::Error::custom(format!(
46            "expected xs:boolean, got: {other}"
47        ))),
48    }
49}
50
51/// Parse error for family XML elements.
52#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize, Default)]
53pub enum FamilyParseError {
54    /// A required XML attribute was absent.
55    MissingAttribute(String),
56    /// An unrecognised element type was encountered.
57    UnknownElementType(String),
58    /// A debugvar declaration could not be parsed.
59    MalformedDebugvar(String),
60    /// Hit an unimplemented content-parse branch.
61    #[default]
62    UnimplementedContent,
63}
64
65impl std::fmt::Display for FamilyParseError {
66    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67        match self {
68            Self::MissingAttribute(attr) => write!(f, "missing attribute: {attr}"),
69            Self::UnknownElementType(tag) => write!(f, "unknown element type: {tag}"),
70            Self::MalformedDebugvar(msg) => write!(f, "malformed debugvar: {msg}"),
71            Self::UnimplementedContent => write!(f, "unimplemented content-parse branch"),
72        }
73    }
74}
75
76impl std::error::Error for FamilyParseError {}
77
78impl From<FamilyParseError> for crate::Error {
79    fn from(value: FamilyParseError) -> Self {
80        Self::Family(value)
81    }
82}
83
84#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize, Default)]
85/// Represents [PDSC Family](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html)
86pub struct Family<'a> {
87    #[serde(rename = "Dfamily")]
88    /// The device family name
89    pub device_family: String,
90
91    #[serde(rename = "Dvendor")]
92    /// The device manufacturer/vendor; valid values: [DeviceVendorEnum](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/packFormat.html)
93    pub vendor: String,
94
95    /// Date this family was deprecated (`xs:date`, e.g. `2020-01-01`)
96    pub deprecated: Option<String>,
97
98    /// Brief family description (0..*)
99    #[serde(rename = "description", default)]
100    pub description: Vec<String>,
101
102    /// Processor definitions (0..*)
103    #[serde(rename = "processor", default)]
104    pub processor: Vec<Processor>,
105
106    /// Compile-time definitions (0..*)
107    #[serde(rename = "compile", default)]
108    pub compile: Vec<Compile>,
109
110    /// Debug unit assignments (0..*)
111    #[serde(rename = "debug", default)]
112    pub debug: Vec<FamilyDebug>,
113
114    /// Debug configuration (0..1)
115    pub debugconfig: Option<DebugConfig>,
116
117    /// Debug port definitions (0..*)
118    #[serde(rename = "debugport", default)]
119    pub debugport: Vec<DebugPort>,
120
121    /// Access port v1 definitions (0..*)
122    #[serde(rename = "accessportV1", default)]
123    pub access_port_v1: Vec<AccessPortV1>,
124
125    /// Access port v2 definitions (0..*)
126    #[serde(rename = "accessportV2", default)]
127    pub access_port_v2: Vec<AccessPortV2>,
128
129    /// Flash programming algorithms (0..*)
130    #[serde(rename = "algorithm", default)]
131    pub algorithm: Vec<Algorithm>,
132
133    /// Raw `<flashinfo>` nodes; see [`FlashInfo`]'s `TryFrom<Node>` impl for why these are deferred.
134    #[serde(rename = "flashinfo", default, borrow, skip_serializing)]
135    pub flashinfo_raw: Vec<RawNode<'a>>,
136
137    /// Flash information (0..*), populated from [`Self::flashinfo_raw`] by [`parse_flashinfo`]
138    #[serde(skip_deserializing)]
139    pub flashinfo: Vec<FlashInfo>,
140
141    /// Memory regions (0..*)
142    #[serde(rename = "memory", default)]
143    pub memory: Vec<Memory>,
144
145    /// Trace unit definitions (0..*)
146    #[serde(rename = "trace", default)]
147    pub trace: Vec<Trace>,
148
149    /// Reference documentation (0..*)
150    #[serde(rename = "book", default)]
151    pub book: Vec<Book>,
152
153    /// Feature descriptors (0..*)
154    #[serde(rename = "feature", default)]
155    pub feature: Vec<Feature>,
156
157    /// Tool environment entries (0..*)
158    #[serde(rename = "environment", default)]
159    pub environment: Vec<FamilyEnvironment>,
160
161    /// Sub-family groupings within this family (0..*)
162    #[serde(rename = "subFamily", default)]
163    pub sub_families: Vec<SubFamily<'a>>,
164
165    /// Devices directly in this family, without a sub-family grouping (0..*)
166    #[serde(rename = "device", default)]
167    pub devices: Vec<Device<'a>>,
168
169    /// Raw `<debugvars>` nodes; see [`merge_debugvars`] for why these are deferred.
170    #[serde(rename = "debugvars", default, borrow, skip_serializing)]
171    pub debugvars_raw: Vec<RawNode<'a>>,
172
173    /// Global debug variables, merged from [`Self::debugvars_raw`] by [`merge_debugvars`]
174    #[serde(skip_deserializing)]
175    pub debugvars: Debugvars,
176
177    /// Raw `<sequences>` nodes; see [`merge_sequences`] for why these are deferred.
178    #[serde(rename = "sequences", default, borrow, skip_serializing)]
179    pub sequences_raw: Vec<RawNode<'a>>,
180
181    /// Debug sequences, merged from [`Self::sequences_raw`] by [`merge_sequences`]
182    #[serde(skip_deserializing)]
183    pub sequences: Sequences<'a>,
184}
185
186#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize, Default)]
187/// Represents the `traceSetput` attribute in [PDSC sequences](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_sequences)
188pub enum TraceSetup {
189    #[serde(rename = "full")]
190    Full,
191    #[serde(rename = "legacy")]
192    #[default]
193    Legacy,
194}
195
196/// Deserializes an `Option<TraceSetup>` from a `TraceSetupEnum` string ("full", "legacy").
197///
198/// `traceSetup` is an XML *attribute* on `<sequences>` (see `PACK.xsd`), and `serde_roxmltree`'s
199/// structural enum support only matches variants against sibling/attribute *tag names*, not
200/// against the text *value* of a single attribute. A plain `#[derive(Deserialize)]` enum field
201/// therefore fails with `Error::MissingNode` as soon as the attribute is actually present, so the
202/// value is parsed manually here instead, mirroring [`de_opt_bool`].
203///
204/// Only called when the attribute is present; absent attributes use `default` (`None`).
205fn de_opt_trace_setup<'de, D>(d: D) -> Result<Option<TraceSetup>, D::Error>
206where
207    D: serde::Deserializer<'de>,
208{
209    let s = String::deserialize(d)?;
210    match s.as_str() {
211        "full" => Ok(Some(TraceSetup::Full)),
212        "legacy" => Ok(Some(TraceSetup::Legacy)),
213        other => Err(serde::de::Error::custom(format!(
214            "expected TraceSetupEnum, got: {other}"
215        ))),
216    }
217}
218
219#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize, Default)]
220/// Represents [PDSC Debugvars](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_debugvars)
221pub struct Debugvars {
222    /// The relative path to the configuration file containing debugvars
223    pub configfile: Option<String>,
224
225    /// Debugvars version
226    pub version: Option<String>,
227
228    #[serde(rename = "#content")]
229    /// Debugvars variable declarations
230    pub content: String,
231
232    /// Parsed debugvars, initially `None`, generated by [Debugvars::parse_debugvars]
233    pub parsed_debugvars: Option<HashMap<String, u64>>,
234}
235
236impl Debugvars {
237    /// Parses a debugvar value string into u64
238    fn parse_value_string(value: &str) -> Option<u64> {
239        // Try to parse the value as a hex value firs
240        if let Some(hex_value_str) = value.strip_prefix("0x")
241            && let Ok(k) = u64::from_str_radix(hex_value_str, 16)
242        {
243            return Some(k);
244        }
245
246        // If not hex, parse as base-10
247        match value.parse() {
248            Ok(k) => Some(k),
249            Err(e) => {
250                error!("Failed to parse debugvar value ({value}) to u64 with error: {e}");
251                None
252            }
253        }
254    }
255
256    /// Parses a single variable declaration entry.
257    ///
258    /// Returns `Ok((name, value))` for a valid `__var name = value;` declaration.
259    ///
260    /// # Errors
261    ///
262    /// Returns [`FamilyParseError::MalformedDebugvar`] if the line is not a valid `__var` declaration.
263    pub fn parse_single_debugvar(line: &str) -> Result<(String, u64), FamilyParseError> {
264        trace!("Parsing debugvar line: {line}");
265
266        // Remove comments
267        let declaration = if line.trim_start().starts_with("//") {
268            let parts: Vec<&str> = line.split('\n').collect();
269            match parts.get(1) {
270                Some(v) => v.trim(),
271                None => {
272                    return Err(FamilyParseError::MalformedDebugvar(
273                        "Unable to get comment body".to_string(),
274                    ));
275                }
276            }
277        } else {
278            line.trim()
279        };
280
281        if declaration.is_empty() {
282            return Err(FamilyParseError::MalformedDebugvar(
283                "empty declaration".to_string(),
284            ));
285        }
286
287        let Some(stripped_declaration) = declaration.strip_prefix("__var") else {
288            warn!("Variable in debugvars does not start with \"__var \": {declaration:?}");
289            return Err(FamilyParseError::MalformedDebugvar(format!(
290                "missing '__var' prefix: {declaration:?}"
291            )));
292        };
293
294        let parts: Vec<&str> = stripped_declaration.split('=').collect();
295        if parts.len() != 2 {
296            warn!("Got something other than 2 fields when parsing debugvar: {parts:?}");
297            return Err(FamilyParseError::MalformedDebugvar(format!(
298                "expected exactly one '=' separator, got {} fields",
299                parts.len()
300            )));
301        }
302
303        let name: String = if let Some(v) = parts.first() {
304            v.trim().to_string()
305        } else {
306            return Err(FamilyParseError::MalformedDebugvar(
307                "Unable to variable name in declaration".to_string(),
308            ));
309        };
310        let value_str = if let Some(v) = parts.get(1) {
311            v.trim()
312        } else {
313            return Err(FamilyParseError::MalformedDebugvar(
314                "Unable to variable value in declaration".to_string(),
315            ));
316        };
317
318        Self::parse_value_string(value_str).map_or_else(
319            || {
320                Err(FamilyParseError::MalformedDebugvar(format!(
321                    "could not parse value as u64: {value_str:?}"
322                )))
323            },
324            |value| Ok((name, value)),
325        )
326    }
327
328    /// Parses the debugvars content and returns a hashmap with the variable name as the key and the value as the value
329    #[must_use]
330    pub fn parse_debugvars_content(&self) -> HashMap<String, u64> {
331        // Remove any lines starting with "//"
332        let content: String = self
333            .content
334            .split('\n')
335            .filter_map(|line| {
336                if line.trim().starts_with("//") {
337                    trace!("Ignoring line: {line}");
338                    None
339                } else {
340                    Some(line.to_owned() + "\n") // Add back the newline
341                }
342            })
343            .collect();
344
345        // Variables are split with a ';'
346        // While unlikely the spec does not forbid multiple inline assignments, e.g.:
347        //    __var foo = 5; __var bar = 0x42;
348        // As such we must split on ';' rather than '\n' for actual parsing.
349        let variables: Vec<&str> = content.split(';').collect();
350
351        variables
352            .iter()
353            .filter_map(|var| {
354                // Silently skip empty segments and malformed lines
355                Self::parse_single_debugvar(var).ok()
356            })
357            .collect()
358    }
359
360    /// Performs the parsing and stores values in [Self::parsed_debugvars]
361    pub fn parse_debugvars(&mut self) {
362        let vars = self.parse_debugvars_content();
363
364        self.parsed_debugvars = Some(vars);
365    }
366}
367
368/// Merges repeated `<debugvars>` sibling elements into a single [`Debugvars`].
369///
370/// `PACK.xsd`'s `DevicePropertiesGroup` models `<debugvars>` (along with several other elements)
371/// as a member of an `xs:choice` with `maxOccurs="unbounded"`, so more than one `<debugvars>` may
372/// legally appear as a sibling at the family/subFamily/device/variant level. Since [`Debugvars`]
373/// is not a `Vec`-based field, the raw nodes are captured separately (see e.g. [`Family::debugvars_raw`])
374/// and merged here: variable-declaration content is concatenated in document order (so
375/// [`Debugvars::parse_debugvars`] can be run once on the result), and the first non-empty
376/// `configfile`/`version` value wins.
377///
378/// # Errors
379///
380/// Returns [`crate::Error::SerdeRoxmltree`] if any raw `<debugvars>` node fails to parse.
381pub fn merge_debugvars(raw_nodes: &[RawNode<'_>]) -> Result<Debugvars, crate::Error> {
382    let mut merged = Debugvars::default();
383    let mut contents: Vec<String> = Vec::new();
384
385    for node in raw_nodes {
386        let parsed: Debugvars = serde_roxmltree::from_node(node.0)?;
387
388        if merged.configfile.is_none() {
389            merged.configfile = parsed.configfile;
390        }
391        if merged.version.is_none() {
392            merged.version = parsed.version;
393        }
394        if !parsed.content.is_empty() {
395            contents.push(parsed.content);
396        }
397    }
398
399    merged.content = contents.join("\n");
400
401    Ok(merged)
402}
403
404/// Represents a [PDSC processor](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_processor) element
405#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
406pub struct Processor {
407    /// Processor instance name for multi-core devices
408    #[serde(rename = "Pname")]
409    pub pname: Option<String>,
410    /// Number of processor units for multi-core devices
411    #[serde(rename = "Punits")]
412    pub punits: Option<u32>,
413    /// Processor core; valid values: [DcoreEnum](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/packFormat.html)
414    #[serde(rename = "Dcore")]
415    pub dcore: Option<String>,
416    /// Processor core architecture version
417    #[serde(rename = "DcoreVersion")]
418    pub dcore_version: Option<String>,
419    /// Floating point unit; valid values: [DfpuEnum](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/packFormat.html)
420    #[serde(rename = "Dfpu")]
421    pub dfpu: Option<String>,
422    /// Memory protection unit; valid values: [DmpuEnum](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/packFormat.html)
423    #[serde(rename = "Dmpu")]
424    pub dmpu: Option<String>,
425    /// DSP instructions support; valid values: [DdspEnum](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/packFormat.html)
426    #[serde(rename = "Ddsp")]
427    pub ddsp: Option<String>,
428    /// M-Profile Vector Extension (Helium); valid values: [DmveEnum](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/packFormat.html)
429    #[serde(rename = "Dmve")]
430    pub dmve: Option<String>,
431    /// Pointer Authentication and Branch Target Identification; valid values: [DpacbtiEnum](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/packFormat.html)
432    #[serde(rename = "Dpacbti")]
433    pub dpacbti: Option<String>,
434    /// TrustZone support; valid values: [DtzEnum](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/packFormat.html)
435    #[serde(rename = "Dtz")]
436    pub dtz: Option<String>,
437    /// Endianness; valid values: [DendianEnum](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/packFormat.html)
438    #[serde(rename = "Dendian")]
439    pub dendian: Option<String>,
440    /// Maximum processor clock frequency in Hz
441    #[serde(rename = "Dclock")]
442    pub dclock: Option<u64>,
443}
444
445/// Represents a [PDSC compile](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_compile) element
446#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
447pub struct Compile {
448    /// Processor instance name for multi-core devices
449    #[serde(rename = "Pname")]
450    pub pname: Option<String>,
451    /// Include file path injected into all projects
452    pub header: Option<String>,
453    /// Preprocessor define injected into all projects
454    pub define: Option<String>,
455    /// Processor-specific preprocessor define
456    #[serde(rename = "Pdefine")]
457    pub pdefine: Option<String>,
458}
459
460/// Represents a [PDSC debug](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_debug) element
461#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
462pub struct FamilyDebug {
463    /// Processor instance name
464    #[serde(rename = "Pname")]
465    pub pname: Option<String>,
466    /// Processor unit index for multi-core devices
467    #[serde(rename = "Punit")]
468    pub punit: Option<u32>,
469    /// Path to the SVD file describing the device registers
470    pub svd: Option<String>,
471    /// Debug port index
472    #[serde(rename = "__dp")]
473    pub dp: Option<u32>,
474    /// Access port index (legacy; use `apid` when possible)
475    #[serde(rename = "__ap")]
476    pub ap: Option<u32>,
477    /// Access port identifier
478    #[serde(rename = "__apid")]
479    pub apid: Option<u32>,
480    /// Base address of the debug component
481    pub address: Option<String>,
482    /// Default debug sequence used to reset this debug unit
483    #[serde(rename = "defaultResetSequence")]
484    pub default_reset_sequence: Option<String>,
485    /// Data patches applied to this debug unit (0..*)
486    #[serde(rename = "datapatch", default)]
487    pub datapatch: Vec<DataPatch>,
488}
489
490/// Represents a [PDSC datapatch](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_datapatch) element
491#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
492pub struct DataPatch {
493    /// Access type; valid values: `AP`, `Mem`
494    #[serde(rename = "type")]
495    pub patch_type: Option<String>,
496    /// Address to patch (hex or decimal string)
497    #[serde(deserialize_with = "de_uint")]
498    pub address: u32,
499    /// Debug port index
500    #[serde(rename = "__dp")]
501    pub dp: Option<u32>,
502    /// Access port index
503    #[serde(rename = "__ap")]
504    pub ap: Option<u32>,
505    /// Value to write during the patch (hex or decimal string)
506    #[serde(deserialize_with = "de_uint")]
507    pub value: u32,
508    /// Optional bitmask applied to the patch
509    pub mask: Option<String>,
510    /// Descriptive text about the patch
511    pub info: Option<String>,
512    /// Access port identifier
513    #[serde(rename = "__apid")]
514    pub apid: Option<u32>,
515}
516
517/// Represents a [PDSC debugconfig](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_debugconfig) element
518#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
519pub struct DebugConfig {
520    /// Default debug interface (`swd`, `jtag`, `cjtag`)
521    pub default: Option<String>,
522    /// Default debug clock frequency in Hz
523    pub clock: Option<u64>,
524    /// SWJ-DP is available (supports both SWD and JTAG)
525    #[serde(default, deserialize_with = "de_opt_bool")]
526    pub swj: Option<bool>,
527    /// Dormant state is supported
528    #[serde(default, deserialize_with = "de_opt_bool")]
529    pub dormant: Option<bool>,
530    /// Path to the debugger system description file
531    pub sdf: Option<String>,
532}
533
534/// Represents a [PDSC debugport](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_debugport) element
535#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
536pub struct DebugPort {
537    /// Debug port index
538    #[serde(rename = "__dp")]
539    pub dp: Option<u32>,
540    /// JTAG port configuration
541    pub jtag: Option<DebugPortJtag>,
542    /// SWD port configuration
543    pub swd: Option<DebugPortSwd>,
544}
545
546/// JTAG debug port parameters
547#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
548pub struct DebugPortJtag {
549    /// TAP index on the JTAG chain
550    #[serde(rename = "tapindex", default, deserialize_with = "de_opt_uint")]
551    pub tapindex: Option<u32>,
552    /// JTAG IDCODE value
553    #[serde(default, deserialize_with = "de_opt_uint")]
554    pub idcode: Option<u32>,
555    /// Target selection value (SWD-DP multidrop)
556    #[serde(default, deserialize_with = "de_opt_uint")]
557    pub targetsel: Option<u32>,
558    /// Instruction register length in bits
559    pub irlen: Option<u32>,
560}
561
562/// SWD debug port parameters
563#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
564pub struct DebugPortSwd {
565    /// SWD-DP IDCODE value
566    #[serde(default, deserialize_with = "de_opt_uint")]
567    pub idcode: Option<u32>,
568    /// Target selection value (SWD-DP multidrop)
569    #[serde(default, deserialize_with = "de_opt_uint")]
570    pub targetsel: Option<u32>,
571}
572
573/// Represents a [PDSC accessportV1](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_accessportV1) element
574#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
575pub struct AccessPortV1 {
576    /// Access port identifier
577    #[serde(rename = "__apid")]
578    pub apid: u32,
579    /// Parent debug port index
580    #[serde(rename = "__dp")]
581    pub dp: Option<u32>,
582    /// APv1 index on the debug port
583    pub index: u32,
584    /// HPROT bus attribute bits
585    #[serde(rename = "HPROT")]
586    pub hprot: Option<u32>,
587    /// Secure privileged access enable
588    #[serde(rename = "SPROT")]
589    pub sprot: Option<u32>,
590}
591
592/// Represents a [PDSC accessportV2](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_accessportV2) element
593#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
594pub struct AccessPortV2 {
595    /// Access port identifier
596    #[serde(rename = "__apid")]
597    pub apid: u32,
598    /// Parent debug port index
599    #[serde(rename = "__dp")]
600    pub dp: Option<u32>,
601    /// Base address of the access port
602    pub address: String,
603    /// HPROT bus attribute bits
604    #[serde(rename = "HPROT")]
605    pub hprot: Option<u32>,
606    /// Secure privileged access enable
607    #[serde(rename = "SPROT")]
608    pub sprot: Option<u32>,
609    /// Parent access port identifier for hierarchical APv2
610    pub parent: Option<u32>,
611}
612
613/// Returns the XSD default value (`"Little-endian"`) for [`Algorithm::endian`]
614fn default_algorithm_endian() -> String {
615    "Little-endian".to_string()
616}
617
618/// Represents a [PDSC algorithm](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_algorithm) element
619#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
620pub struct Algorithm {
621    /// Path to the flash algorithm file (.FLM)
622    pub name: String,
623    /// Start address of the flash region (hex string, e.g. `"0x00000000"`)
624    pub start: Option<String>,
625    /// Size of the flash region in bytes (hex string, e.g. `"0x00010000"`)
626    pub size: Option<String>,
627    /// Start address of the RAM buffer used by the algorithm
628    #[serde(rename = "RAMstart")]
629    pub ram_start: Option<String>,
630    /// Size of the RAM buffer in bytes
631    #[serde(rename = "RAMsize")]
632    pub ram_size: Option<String>,
633    /// If `true`, this is the default algorithm for the device
634    #[serde(default, deserialize_with = "de_opt_bool")]
635    pub default: Option<bool>,
636    /// Algorithm style (`Keil` or `IAR`)
637    pub style: Option<String>,
638    /// Processor instance name this algorithm applies to
639    #[serde(rename = "Pname")]
640    pub pname: Option<String>,
641    /// Index of the mounted device this algorithm applies to (only used by board descriptions with multiple mounted devices)
642    #[serde(rename = "deviceIndex")]
643    pub device_index: Option<String>,
644    /// Parameter passed on algorithm invocation
645    pub parameter: Option<String>,
646    /// Endianness of the algorithm; valid values: [DendianEnum](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/packFormat.html); defaults to `"Little-endian"`
647    #[serde(default = "default_algorithm_endian")]
648    pub endian: String,
649}
650
651/// Represents a [PDSC flashinfo](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_flashinfo) element
652#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
653pub struct FlashInfo {
654    /// Name of the flash device
655    pub name: String,
656    /// Start address of the flash device (hex string)
657    pub start: String,
658    /// Flash page size in bytes (hex string)
659    pub pagesize: String,
660    /// Erased-byte value (hex string, usually `"0xFF"`)
661    pub blankval: Option<String>,
662    /// Fill byte value for gaps (hex string)
663    pub filler: Option<String>,
664    /// Page program time in microseconds
665    pub ptime: Option<u32>,
666    /// Sector erase time in microseconds
667    pub etime: Option<u32>,
668    /// Processor instance name this info applies to
669    #[serde(rename = "Pname")]
670    pub pname: Option<String>,
671    /// Contiguous flash blocks and gaps, in document order (0..*)
672    ///
673    /// These are populated by [`FlashInfo`]'s `TryFrom<Node>` impl rather than by [serde_roxmltree]
674    /// directly, since `<block>` and `<gap>` are interleaved children and [serde_roxmltree] can only
675    /// collect repeated children of a single tag name per field.
676    #[serde(skip_deserializing)]
677    pub elements: Vec<FlashInfoElement>,
678}
679
680impl<'a, 'input: 'a> TryFrom<Node<'a, 'input>> for FlashInfo {
681    type Error = crate::Error;
682
683    fn try_from(value: Node<'a, 'input>) -> Result<Self, Self::Error> {
684        let mut info: Self = serde_roxmltree::from_node(value)?;
685
686        for child in value.children().filter(roxmltree::Node::is_element) {
687            info.elements.push(child.try_into()?);
688        }
689
690        Ok(info)
691    }
692}
693
694/// Parses raw `<flashinfo>` nodes into [`FlashInfo`]s, preserving `<block>`/`<gap>` document order
695///
696/// # Errors
697///
698/// Returns [`crate::Error::Family`] if any raw flashinfo node fails to parse.
699pub fn parse_flashinfo(raw_nodes: &[RawNode<'_>]) -> Result<Vec<FlashInfo>, crate::Error> {
700    raw_nodes
701        .iter()
702        .map(|node| {
703            node.0.try_into().inspect_err(|e| {
704                error!("Failed to parse flashinfo node `{node:#?}` with err `{e:#?}`");
705            })
706        })
707        .collect()
708}
709
710/// A contiguous block within a flash device
711#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
712pub struct FlashBlock {
713    /// Count of sectors in this block
714    #[serde(deserialize_with = "de_uint")]
715    pub count: u32,
716    /// Sector size in bytes (hex string)
717    pub size: String,
718    /// Optional argument to pass to a sequence that is part of a flash operation
719    pub arg: Option<String>,
720}
721
722/// A gap between flash regions
723#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
724pub struct FlashGap {
725    /// Gap sector size in bytes (hex string)
726    pub size: String,
727}
728
729/// Represents the valid `<flashinfo>` child elements, with document order preserved
730#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
731pub enum FlashInfoElement {
732    /// A contiguous flash block, see [FlashBlock]
733    Block(FlashBlock),
734    /// A gap between flash regions, see [FlashGap]
735    Gap(FlashGap),
736}
737
738impl Default for FlashInfoElement {
739    fn default() -> Self {
740        Self::Block(FlashBlock::default())
741    }
742}
743
744impl<'a, 'input: 'a> TryFrom<Node<'a, 'input>> for FlashInfoElement {
745    type Error = crate::Error;
746
747    fn try_from(value: Node<'a, 'input>) -> Result<Self, Self::Error> {
748        if !value.is_element() {
749            // Text/comment nodes are not flashinfo elements; content-parse is unimplemented
750            return Err(FamilyParseError::UnimplementedContent.into());
751        }
752        match value.tag_name().name().to_lowercase().as_str() {
753            "block" => Ok(Self::Block(serde_roxmltree::from_node(value)?)),
754            "gap" => Ok(Self::Gap(serde_roxmltree::from_node(value)?)),
755            other => Err(FamilyParseError::UnknownElementType(other.to_string()).into()),
756        }
757    }
758}
759
760/// Represents a [PDSC memory](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_memory) element
761#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
762pub struct Memory {
763    /// Unique name for this memory region
764    pub name: Option<String>,
765    /// Access permissions (`r`, `rw`, `rwx`, etc.)
766    pub access: Option<String>,
767    /// Start address of the memory region (hex string)
768    pub start: String,
769    /// Size of the memory region in bytes (hex string)
770    pub size: String,
771    /// If `true`, this is the default memory region
772    #[serde(default, deserialize_with = "de_opt_bool")]
773    pub default: Option<bool>,
774    /// If `true`, this region contains the startup code
775    #[serde(default, deserialize_with = "de_opt_bool")]
776    pub startup: Option<bool>,
777    /// If `true`, do not zero-initialise this region
778    #[serde(default, deserialize_with = "de_opt_bool")]
779    pub uninit: Option<bool>,
780    /// Name of the memory region this region aliases
781    pub alias: Option<String>,
782    /// Processor instance name this region applies to
783    #[serde(rename = "Pname")]
784    pub pname: Option<String>,
785}
786
787/// Represents a [PDSC trace](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_trace) element
788#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
789pub struct Trace {
790    /// Processor instance name
791    #[serde(rename = "Pname")]
792    pub pname: Option<String>,
793    /// Serial wire trace configurations (0..*)
794    #[serde(rename = "serialwire", default)]
795    pub serialwire: Vec<SerialWire>,
796    /// Parallel trace port configurations (0..*)
797    #[serde(rename = "traceport", default)]
798    pub traceport: Vec<TracePort>,
799    /// Trace buffer configurations (0..*)
800    #[serde(rename = "tracebuffer", default)]
801    pub tracebuffer: Vec<TraceBuffer>,
802}
803
804/// Represents a [PDSC serialwire](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_serialwire) element
805///
806/// This element only defines vendor/tool-specific `anyAttribute` attributes in the schema, none of which are modeled.
807#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
808pub struct SerialWire {
809    // TODO: Handle the `anyAttribute` children
810}
811
812/// Represents a [PDSC traceport](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_traceport) element
813#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
814pub struct TracePort {
815    /// Width of the parallel trace port in bits
816    #[serde(default, deserialize_with = "de_opt_uint")]
817    pub width: Option<u32>,
818}
819
820/// Represents a [PDSC tracebuffer](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_tracebuffer) element
821#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
822pub struct TraceBuffer {
823    /// Start address of the trace buffer (hex string)
824    pub start: Option<String>,
825    /// Size of the trace buffer in bytes (hex string)
826    pub size: Option<String>,
827}
828
829/// Represents a [PDSC book](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_book) element
830#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
831pub struct Book {
832    /// Path or URL to the document
833    pub name: String,
834    /// Human-readable document title
835    pub title: String,
836    /// Processor instance name this book applies to
837    #[serde(rename = "Pname")]
838    pub pname: Option<String>,
839    /// If `true`, this document is public
840    #[serde(default, deserialize_with = "de_opt_bool")]
841    pub public: Option<bool>,
842}
843
844#[allow(clippy::too_long_first_doc_paragraph)]
845/// Represents a [PDSC feature](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_feature) element;
846/// valid `feature_type` values: [DeviceFeatureEnum](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/packFormat.html)
847#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
848pub struct Feature {
849    /// Feature type identifier
850    #[serde(rename = "type")]
851    pub feature_type: String,
852    /// Primary parameter — numeric for most types, label string for `Application`
853    pub n: Option<String>,
854    /// Secondary parameter — numeric for most types, label string for `Application`
855    pub m: Option<String>,
856    /// Human-readable feature name
857    pub name: Option<String>,
858    /// Processor instance name this feature applies to
859    #[serde(rename = "Pname")]
860    pub pname: Option<String>,
861    /// Deprecated; count of identical features (only for backwards compatibility)
862    pub count: Option<i32>,
863}
864
865/// Represents an [environment](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_environment) entry within a family
866#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
867pub struct FamilyEnvironment {
868    /// Tool environment identifier
869    pub name: String,
870    /// Processor instance name
871    #[serde(rename = "Pname")]
872    pub pname: Option<String>,
873}
874
875/// Represents a [PDSC variant](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_variant) element
876///
877/// Defines a named variant of a device, overriding or extending the parent device's properties.
878#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
879pub struct Variant<'a> {
880    /// Variant name
881    #[serde(rename = "Dvariant")]
882    pub variant_name: String,
883    /// Date this variant was deprecated (`xs:date`, e.g. `2020-01-01`)
884    pub deprecated: Option<String>,
885    /// Brief variant description (0..*)
886    #[serde(rename = "description", default)]
887    pub description: Vec<String>,
888    /// Processor definitions (0..*)
889    #[serde(rename = "processor", default)]
890    pub processor: Vec<Processor>,
891    /// Compile-time definitions (0..*)
892    #[serde(rename = "compile", default)]
893    pub compile: Vec<Compile>,
894    /// Debug unit assignments (0..*)
895    #[serde(rename = "debug", default)]
896    pub debug: Vec<FamilyDebug>,
897    /// Debug configuration (0..1)
898    pub debugconfig: Option<DebugConfig>,
899    /// Debug port definitions (0..*)
900    #[serde(rename = "debugport", default)]
901    pub debugport: Vec<DebugPort>,
902    /// Access port v1 definitions (0..*)
903    #[serde(rename = "accessportV1", default)]
904    pub access_port_v1: Vec<AccessPortV1>,
905    /// Access port v2 definitions (0..*)
906    #[serde(rename = "accessportV2", default)]
907    pub access_port_v2: Vec<AccessPortV2>,
908    /// Flash programming algorithms (0..*)
909    #[serde(rename = "algorithm", default)]
910    pub algorithm: Vec<Algorithm>,
911    /// Raw `<flashinfo>` nodes; see [`FlashInfo`]'s `TryFrom<Node>` impl for why these are deferred.
912    #[serde(rename = "flashinfo", default, borrow, skip_serializing)]
913    pub flashinfo_raw: Vec<RawNode<'a>>,
914
915    /// Flash information (0..*), populated from [`Self::flashinfo_raw`] by [`parse_flashinfo`]
916    #[serde(skip_deserializing)]
917    pub flashinfo: Vec<FlashInfo>,
918    /// Memory regions (0..*)
919    #[serde(rename = "memory", default)]
920    pub memory: Vec<Memory>,
921    /// Trace unit definitions (0..*)
922    #[serde(rename = "trace", default)]
923    pub trace: Vec<Trace>,
924    /// Reference documentation (0..*)
925    #[serde(rename = "book", default)]
926    pub book: Vec<Book>,
927    /// Feature descriptors (0..*)
928    #[serde(rename = "feature", default)]
929    pub feature: Vec<Feature>,
930    /// Tool environment entries (0..*)
931    #[serde(rename = "environment", default)]
932    pub environment: Vec<FamilyEnvironment>,
933    /// Raw `<debugvars>` nodes; see [`merge_debugvars`] for why these are deferred.
934    #[serde(rename = "debugvars", default, borrow, skip_serializing)]
935    pub debugvars_raw: Vec<RawNode<'a>>,
936    /// Variant-level debug variables (rare; most packs define these at family level), merged
937    /// from [`Self::debugvars_raw`] by [`merge_debugvars`]
938    #[serde(skip_deserializing)]
939    pub debugvars: Debugvars,
940    /// Raw `<sequences>` nodes; see [`merge_sequences`] for why these are deferred.
941    #[serde(rename = "sequences", default, borrow, skip_serializing)]
942    pub sequences_raw: Vec<RawNode<'a>>,
943    /// Variant-level debug sequences (rare; most packs define these at family level), merged
944    /// from [`Self::sequences_raw`] by [`merge_sequences`]
945    #[serde(skip_deserializing)]
946    pub sequences: Sequences<'a>,
947}
948
949/// Represents a [PDSC device](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_device) element
950#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize, Default)]
951pub struct Device<'a> {
952    /// Device name
953    #[serde(rename = "Dname")]
954    pub device_name: String,
955    /// Date this device was deprecated (`xs:date`, e.g. `2020-01-01`)
956    pub deprecated: Option<String>,
957    /// Brief device description (0..*)
958    #[serde(rename = "description", default)]
959    pub description: Vec<String>,
960    /// Processor definitions (0..*)
961    #[serde(rename = "processor", default)]
962    pub processor: Vec<Processor>,
963    /// Compile-time definitions (0..*)
964    #[serde(rename = "compile", default)]
965    pub compile: Vec<Compile>,
966    /// Debug unit assignments (0..*)
967    #[serde(rename = "debug", default)]
968    pub debug: Vec<FamilyDebug>,
969    /// Debug configuration (0..1)
970    pub debugconfig: Option<DebugConfig>,
971    /// Debug port definitions (0..*)
972    #[serde(rename = "debugport", default)]
973    pub debugport: Vec<DebugPort>,
974    /// Access port v1 definitions (0..*)
975    #[serde(rename = "accessportV1", default)]
976    pub access_port_v1: Vec<AccessPortV1>,
977    /// Access port v2 definitions (0..*)
978    #[serde(rename = "accessportV2", default)]
979    pub access_port_v2: Vec<AccessPortV2>,
980    /// Flash programming algorithms (0..*)
981    #[serde(rename = "algorithm", default)]
982    pub algorithm: Vec<Algorithm>,
983    /// Raw `<flashinfo>` nodes; see [`FlashInfo`]'s `TryFrom<Node>` impl for why these are deferred.
984    #[serde(rename = "flashinfo", default, borrow, skip_serializing)]
985    pub flashinfo_raw: Vec<RawNode<'a>>,
986
987    /// Flash information (0..*), populated from [`Self::flashinfo_raw`] by [`parse_flashinfo`]
988    #[serde(skip_deserializing)]
989    pub flashinfo: Vec<FlashInfo>,
990    /// Memory regions (0..*)
991    #[serde(rename = "memory", default)]
992    pub memory: Vec<Memory>,
993    /// Trace unit definitions (0..*)
994    #[serde(rename = "trace", default)]
995    pub trace: Vec<Trace>,
996    /// Reference documentation (0..*)
997    #[serde(rename = "book", default)]
998    pub book: Vec<Book>,
999    /// Feature descriptors (0..*)
1000    #[serde(rename = "feature", default)]
1001    pub feature: Vec<Feature>,
1002    /// Tool environment entries (0..*)
1003    #[serde(rename = "environment", default)]
1004    pub environment: Vec<FamilyEnvironment>,
1005    /// Raw `<debugvars>` nodes; see [`merge_debugvars`] for why these are deferred.
1006    #[serde(rename = "debugvars", default, borrow, skip_serializing)]
1007    pub debugvars_raw: Vec<RawNode<'a>>,
1008    /// Device-level debug variables (rare; most packs define these at family level), merged
1009    /// from [`Self::debugvars_raw`] by [`merge_debugvars`]
1010    #[serde(skip_deserializing)]
1011    pub debugvars: Debugvars,
1012    /// Raw `<sequences>` nodes; see [`merge_sequences`] for why these are deferred.
1013    #[serde(rename = "sequences", default, borrow, skip_serializing)]
1014    pub sequences_raw: Vec<RawNode<'a>>,
1015    /// Device-level debug sequences (rare; most packs define these at family level), merged
1016    /// from [`Self::sequences_raw`] by [`merge_sequences`]
1017    #[serde(skip_deserializing)]
1018    pub sequences: Sequences<'a>,
1019    /// Device variants (0..*)
1020    #[serde(rename = "variant", default)]
1021    pub variants: Vec<Variant<'a>>,
1022}
1023
1024/// Represents a [PDSC subFamily](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_subFamily) element
1025#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize, Default)]
1026pub struct SubFamily<'a> {
1027    /// Sub-family name
1028    #[serde(rename = "DsubFamily")]
1029    pub sub_family_name: String,
1030    /// Date this sub-family was deprecated (`xs:date`, e.g. `2020-01-01`)
1031    pub deprecated: Option<String>,
1032    /// Brief sub-family description (0..*)
1033    #[serde(rename = "description", default)]
1034    pub description: Vec<String>,
1035    /// Processor definitions (0..*)
1036    #[serde(rename = "processor", default)]
1037    pub processor: Vec<Processor>,
1038    /// Compile-time definitions (0..*)
1039    #[serde(rename = "compile", default)]
1040    pub compile: Vec<Compile>,
1041    /// Debug unit assignments (0..*)
1042    #[serde(rename = "debug", default)]
1043    pub debug: Vec<FamilyDebug>,
1044    /// Debug configuration (0..1)
1045    pub debugconfig: Option<DebugConfig>,
1046    /// Debug port definitions (0..*)
1047    #[serde(rename = "debugport", default)]
1048    pub debugport: Vec<DebugPort>,
1049    /// Access port v1 definitions (0..*)
1050    #[serde(rename = "accessportV1", default)]
1051    pub access_port_v1: Vec<AccessPortV1>,
1052    /// Access port v2 definitions (0..*)
1053    #[serde(rename = "accessportV2", default)]
1054    pub access_port_v2: Vec<AccessPortV2>,
1055    /// Flash programming algorithms (0..*)
1056    #[serde(rename = "algorithm", default)]
1057    pub algorithm: Vec<Algorithm>,
1058    /// Raw `<flashinfo>` nodes; see [`FlashInfo`]'s `TryFrom<Node>` impl for why these are deferred.
1059    #[serde(rename = "flashinfo", default, borrow, skip_serializing)]
1060    pub flashinfo_raw: Vec<RawNode<'a>>,
1061
1062    /// Flash information (0..*), populated from [`Self::flashinfo_raw`] by [`parse_flashinfo`]
1063    #[serde(skip_deserializing)]
1064    pub flashinfo: Vec<FlashInfo>,
1065    /// Memory regions (0..*)
1066    #[serde(rename = "memory", default)]
1067    pub memory: Vec<Memory>,
1068    /// Trace unit definitions (0..*)
1069    #[serde(rename = "trace", default)]
1070    pub trace: Vec<Trace>,
1071    /// Reference documentation (0..*)
1072    #[serde(rename = "book", default)]
1073    pub book: Vec<Book>,
1074    /// Feature descriptors (0..*)
1075    #[serde(rename = "feature", default)]
1076    pub feature: Vec<Feature>,
1077    /// Tool environment entries (0..*)
1078    #[serde(rename = "environment", default)]
1079    pub environment: Vec<FamilyEnvironment>,
1080    /// Raw `<debugvars>` nodes; see [`merge_debugvars`] for why these are deferred.
1081    #[serde(rename = "debugvars", default, borrow, skip_serializing)]
1082    pub debugvars_raw: Vec<RawNode<'a>>,
1083    /// Sub-family-level debug variables, merged from [`Self::debugvars_raw`] by [`merge_debugvars`]
1084    #[serde(skip_deserializing)]
1085    pub debugvars: Debugvars,
1086    /// Raw `<sequences>` nodes; see [`merge_sequences`] for why these are deferred.
1087    #[serde(rename = "sequences", default, borrow, skip_serializing)]
1088    pub sequences_raw: Vec<RawNode<'a>>,
1089    /// Sub-family-level debug sequences, merged from [`Self::sequences_raw`] by [`merge_sequences`]
1090    #[serde(skip_deserializing)]
1091    pub sequences: Sequences<'a>,
1092    /// Devices within this sub-family (0..*)
1093    #[serde(rename = "device", default)]
1094    pub devices: Vec<Device<'a>>,
1095}
1096
1097#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize, Default)]
1098/// Represents [PDSC sequences](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_sequences)
1099pub struct Sequences<'a> {
1100    /// Trace setup configuration
1101    #[serde(
1102        rename = "traceSetup",
1103        default,
1104        deserialize_with = "de_opt_trace_setup"
1105    )]
1106    pub trace_setup: Option<TraceSetup>,
1107
1108    /// Raw XML nodes representing debug sequences
1109    ///
1110    /// These are stored as [RawNode] due to [serde_roxmltree] not supporting decoding elements as
1111    /// a vector of enums and we neet do be able to preresent both [control](SequenceElement::Control)
1112    /// and [block](SequenceElement::Block) elements with their order perserved.
1113    #[serde(rename = "sequence", default)]
1114    #[serde(borrow)]
1115    #[serde(skip_serializing)]
1116    pub raw_nodes: Vec<RawNode<'a>>,
1117
1118    /// Debug Sequences
1119    #[serde(skip_deserializing)]
1120    pub sequences: Vec<Sequence>,
1121}
1122
1123impl Sequences<'_> {
1124    /// Iterates through the raw nodes and parses the sequences
1125    ///
1126    /// # Errors
1127    ///
1128    /// Returns [`crate::Error::Family`] if any raw sequence node fails to parse.
1129    pub fn parse_raw_nodes_content(&self) -> Result<Vec<Sequence>, crate::Error> {
1130        self.raw_nodes
1131            .iter()
1132            .map(|node| {
1133                node.0.try_into().inspect_err(|e| {
1134                    error!("Failed to parse sequence node `{node:#?}` with err `{e:#?}`");
1135                })
1136            })
1137            .collect()
1138    }
1139
1140    /// Parses the raw XML Sequence nodes and stores the parsed sequences in [Self::sequences]
1141    ///
1142    /// # Errors
1143    ///
1144    /// Returns [`crate::Error::Family`] if any sequence node fails to parse; see [`Self::parse_raw_nodes_content`].
1145    pub fn parse_sequences(&mut self) -> Result<(), crate::Error> {
1146        let sequences = Self::parse_raw_nodes_content(self)?;
1147
1148        self.sequences = sequences;
1149
1150        Ok(())
1151    }
1152}
1153
1154/// Merges repeated `<sequences>` sibling elements into a single [`Sequences`].
1155///
1156/// `PACK.xsd`'s `DevicePropertiesGroup` models `<sequences>` (along with several other elements)
1157/// as a member of an `xs:choice` with `maxOccurs="unbounded"`, so more than one `<sequences>` may
1158/// legally appear as a sibling at the family/subFamily/device/variant level. Since [`Sequences`]
1159/// is not a `Vec`-based field, the raw nodes are captured separately (see e.g. [`Family::sequences_raw`])
1160/// and merged here: the `<sequence>` children of every sibling are concatenated in document order,
1161/// and the first non-`None` `traceSetup` value wins.
1162///
1163/// # Errors
1164///
1165/// Returns [`crate::Error::SerdeRoxmltree`] if any raw `<sequences>` node fails to parse.
1166pub fn merge_sequences<'a>(raw_nodes: &[RawNode<'a>]) -> Result<Sequences<'a>, crate::Error> {
1167    let mut merged = Sequences::default();
1168
1169    for node in raw_nodes {
1170        let parsed: Sequences<'a> = serde_roxmltree::from_node(node.0)?;
1171
1172        if merged.trace_setup.is_none() {
1173            merged.trace_setup = parsed.trace_setup;
1174        }
1175        merged.raw_nodes.extend(parsed.raw_nodes);
1176    }
1177
1178    Ok(merged)
1179}
1180
1181#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize, Default)]
1182/// Represents [PDSC Sequence](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_sequence)
1183pub struct Sequence {
1184    /// The sequence name
1185    pub name: String,
1186
1187    /// Processor name, if set only use the debug sequence for this processor
1188    pub processor_name: Option<String>,
1189
1190    /// If set disable the [Predefined Debug Access Sequence](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/debug_description.html#default_sequences) of the same name
1191    pub disable: Option<bool>,
1192
1193    /// Descriptive text about the sequence
1194    pub info: Option<String>,
1195
1196    #[serde(skip_serializing)]
1197    pub elements: Vec<SequenceElement>,
1198}
1199
1200impl<'a, 'input: 'a> TryFrom<Node<'a, 'input>> for Sequence {
1201    type Error = crate::Error;
1202
1203    fn try_from(value: Node<'a, 'input>) -> Result<Self, Self::Error> {
1204        // Validate that this is a sequence node
1205        let node_name = value.tag_name().name();
1206        if node_name != "sequence" {
1207            return Err(FamilyParseError::UnknownElementType(node_name.to_string()).into());
1208        }
1209
1210        // Get the name
1211        let sequence_name = value
1212            .attribute("name")
1213            .ok_or_else(|| FamilyParseError::MissingAttribute("name".to_string()))?;
1214
1215        // Get the optional attributes
1216        let sequence_processor_name = value
1217            .attribute("Pname")
1218            .map_or_else(|| None, |v| Some(v.to_string()));
1219        let sequence_disable = {
1220            value.attribute("disable").and_then(|v| {
1221                let disable_value: bool = match v.parse() {
1222                    Ok(k) => k,
1223                    Err(e) => {
1224                        error!("Failed to parse non-boolean value `{v}` with error `{e:#?}`");
1225                        return None;
1226                    }
1227                };
1228                Some(disable_value)
1229            })
1230        };
1231        let sequence_info = value
1232            .attribute("info")
1233            .map_or_else(|| None, |v| Some(v.to_string()));
1234
1235        // The sequence elements
1236        let mut elements: Vec<SequenceElement> = Vec::new();
1237
1238        // Try to parse the child nodes
1239        for child in value.children().filter(roxmltree::Node::is_element) {
1240            let element: SequenceElement = child.try_into()?;
1241
1242            elements.push(element);
1243        }
1244
1245        Ok(Self {
1246            name: sequence_name.to_string(),
1247            processor_name: sequence_processor_name,
1248            disable: sequence_disable,
1249            info: sequence_info,
1250            elements,
1251        })
1252    }
1253}
1254
1255impl<'a, 'input: 'a> TryFrom<Node<'a, 'input>> for SequenceElement {
1256    type Error = crate::Error;
1257
1258    fn try_from(value: Node<'a, 'input>) -> Result<Self, Self::Error> {
1259        if !value.is_element() {
1260            // Text/comment nodes are not sequence elements; content-parse is unimplemented
1261            return Err(FamilyParseError::UnimplementedContent.into());
1262        }
1263        match value.tag_name().name().to_lowercase().as_str() {
1264            "block" => Ok(<Node<'_, '_> as TryInto<SequenceBlock>>::try_into(value)?.into()),
1265            "control" => Ok(<Node<'_, '_> as TryInto<SequenceControl>>::try_into(value)?.into()),
1266            other => Err(FamilyParseError::UnknownElementType(other.to_string()).into()),
1267        }
1268    }
1269}
1270
1271impl<'a, 'input: 'a> TryFrom<Node<'a, 'input>> for SequenceBlock {
1272    type Error = crate::Error;
1273
1274    fn try_from(value: Node<'a, 'input>) -> Result<Self, Self::Error> {
1275        let mut block: Self = serde_roxmltree::from_node(value)?;
1276        block.parse_statements()?;
1277        Ok(block)
1278    }
1279}
1280
1281impl<'a, 'input: 'a> TryFrom<Node<'a, 'input>> for SequenceControl {
1282    type Error = crate::Error;
1283
1284    fn try_from(value: Node<'a, 'input>) -> Result<Self, Self::Error> {
1285        // Use serde_roxmltree to parse the basic elements
1286        let mut block: Self = serde_roxmltree::from_node(value)?;
1287
1288        // Try to parse the child nodes
1289        for child in value.children().filter(roxmltree::Node::is_element) {
1290            let element: SequenceElement = child.try_into()?;
1291
1292            block.elements.push(element);
1293        }
1294
1295        // Parse the conditional into an Expression
1296        let conditional_string: &str;
1297        if let Some(ref val) = block.conditional_if {
1298            conditional_string = val.as_str();
1299        } else if let Some(ref val) = block.conditional_while {
1300            conditional_string = val.as_str();
1301        } else {
1302            return Err(FamilyParseError::MissingAttribute(
1303                "conditional 'if' or 'while' attribute".to_string(),
1304            )
1305            .into());
1306        }
1307
1308        let conditional: debug_access::Expression = conditional_string.try_into()?;
1309        block.conditional = Some(conditional);
1310
1311        Ok(block)
1312    }
1313}
1314
1315#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
1316/// Represents the valid sequence child elements as defined in the "Child Elements" section of the [PDSC sequence element](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_sequence)
1317pub enum SequenceElement {
1318    /// A PDSC Control sequence, see [SequenceControl]
1319    Control(SequenceControl),
1320    /// A PDSC Block sequence, see [SequenceBlock]
1321    Block(SequenceBlock),
1322}
1323
1324impl Default for SequenceElement {
1325    fn default() -> Self {
1326        Self::Block(SequenceBlock::default())
1327    }
1328}
1329
1330#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize, Default)]
1331/// Represents a [PDSC Control Sequence](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_seq_control)
1332pub struct SequenceControl {
1333    /// If conditional
1334    #[serde(rename = "if")]
1335    pub conditional_if: Option<String>,
1336
1337    /// While conditional
1338    #[serde(rename = "while")]
1339    pub conditional_while: Option<String>,
1340
1341    /// Timeout in microseconds, a value of 0 is the same as None
1342    pub timeout: Option<u64>,
1343
1344    /// Decsriptive text, e.g. for diagnostics
1345    pub info: Option<String>,
1346
1347    #[serde(skip_deserializing)]
1348    /// The elements contained by the control block
1349    pub elements: Vec<SequenceElement>,
1350
1351    #[serde(skip_deserializing)]
1352    /// The conditional parsed as an Expression
1353    ///
1354    /// The [Expression](debug_access::Expression) is wrapped in an [Option] due to
1355    /// provoding a default value for [serde] when deserializing. It should be safe
1356    /// to unwrap this value.
1357    pub conditional: Option<debug_access::Expression>,
1358}
1359
1360impl From<SequenceControl> for SequenceElement {
1361    fn from(value: SequenceControl) -> Self {
1362        Self::Control(value)
1363    }
1364}
1365
1366#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize, Default)]
1367/// Represents a [PDSC Block Sequence](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_seq_block)
1368pub struct SequenceBlock {
1369    /// If `Some(true)` the block must be executed atomically, see the description on CMSIS Pack website.
1370    pub atomic: Option<bool>,
1371
1372    /// Decsriptive text, e.g. for diagnostics
1373    pub info: Option<String>,
1374
1375    #[serde(rename = "#content")]
1376    /// Sequence block content
1377    pub content: String,
1378
1379    #[serde(skip_deserializing)]
1380    /// [Statement]s resulting from the parsing of [Self::content]
1381    pub statements: Vec<Statement>,
1382}
1383
1384impl SequenceBlock {
1385    /// Parses [Self::content] into a list of [Statement]s
1386    ///
1387    /// # Errors
1388    ///
1389    /// Returns [`crate::Error::Debug`] if any statement line fails to parse.
1390    pub fn parse_statements_content(&self) -> Result<Vec<Statement>, crate::Error> {
1391        self.content
1392            .lines()
1393            .flat_map(|line| line.split(';'))
1394            .map(str::trim)
1395            .filter(|s| !s.is_empty())
1396            .map(|s| Statement::try_from(s.to_string()))
1397            .collect()
1398    }
1399
1400    /// Parses the block content and stores the result in [Self::statements]
1401    ///
1402    /// # Errors
1403    ///
1404    /// Returns [`crate::Error::Debug`] if any statement line fails to parse; see [`Self::parse_statements_content`].
1405    pub fn parse_statements(&mut self) -> Result<(), crate::Error> {
1406        self.statements = self.parse_statements_content()?;
1407
1408        Ok(())
1409    }
1410}
1411
1412impl From<SequenceBlock> for SequenceElement {
1413    fn from(value: SequenceBlock) -> Self {
1414        Self::Block(value)
1415    }
1416}
1417
1418#[cfg(test)]
1419mod tests {
1420    use roxmltree::Document;
1421    use serde_roxmltree::RawNode;
1422
1423    use crate::{
1424        debug_access::{
1425            Assignment, DebugFunction, Expression,
1426            Statement::{self},
1427        },
1428        family::{
1429            FamilyParseError, FlashBlock, FlashGap, FlashInfoElement, Sequence, SequenceBlock,
1430            SequenceControl, SequenceElement, TraceSetup, parse_flashinfo,
1431        },
1432    };
1433
1434    #[test]
1435    fn basic_sequence() {
1436        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
1437<sequence name="ResetSystem">
1438    <block>
1439        Sequence("ResetAndHalt");
1440    </block>
1441</sequence>"#;
1442
1443        let document = Document::parse(xml_str).unwrap();
1444        let sequence_node = document.root_element();
1445        let raw_node: RawNode = RawNode(sequence_node);
1446
1447        let sequence: Sequence = raw_node.0.try_into().unwrap();
1448
1449        assert_eq!(sequence.name, "ResetSystem".to_string());
1450        assert_eq!(
1451            sequence.elements,
1452            vec![
1453                SequenceBlock {
1454                    atomic: None,
1455                    info: None,
1456                    content: "\n        Sequence(\"ResetAndHalt\");\n    ".to_string(),
1457                    statements: vec![Statement::Expression(Expression::FunctionCall(Box::new(
1458                        DebugFunction::Sequence {
1459                            name: Expression::Normal("\"ResetAndHalt\"".to_string())
1460                        }
1461                    )))]
1462                }
1463                .into()
1464            ]
1465        );
1466    }
1467
1468    #[test]
1469    /// Tests the example sequence from https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/pdsc_family_pg.html#element_sequence
1470    fn full_sequence() {
1471        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
1472<sequence name="UserSequence">
1473    <block info="Define variables and do debug accesses">
1474        __var tpWidth = (__traceout &amp; 0x003F0000) >> 16;
1475    </block>
1476
1477    <control if="__traceout &amp; 0x2" info="Parallel Trace Port enabled">
1478        <block>
1479            // Do something generic for parallel trace port trace
1480        </block>
1481
1482        <control if="tpWidth == 1" info="Configure device for 1-bit TPIU trace.">
1483            <block>
1484                // Do debug accesses
1485            </block>
1486        </control>
1487
1488        <control if="tpWidth == 2" info="Configure device for 2-bit TPIU trace.">
1489            <block>
1490                // Do debug accesses
1491            </block>
1492        </control>
1493
1494        <control if="tpWidth == 4" info="Configure device for 4-bit TPIU trace.">
1495            <block>
1496                // Do debug accesses
1497            </block>
1498        </control>
1499    </control>
1500</sequence>"#;
1501
1502        let document = Document::parse(xml_str).unwrap();
1503        let sequence_node = document.root_element();
1504        let raw_node: RawNode = RawNode(sequence_node);
1505
1506        let sequence: Sequence = raw_node.0.try_into().unwrap();
1507
1508        // Check basic info
1509        assert_eq!(sequence.name, "UserSequence".to_string());
1510        assert_eq!(sequence.disable, None);
1511        assert_eq!(sequence.info, None);
1512        assert_eq!(sequence.processor_name, None);
1513
1514        // Define a repeated element for future use
1515        let debug_access_block: SequenceElement = SequenceBlock {
1516            atomic: None,
1517            info: None,
1518            content: r#"
1519                // Do debug accesses
1520            "#
1521            .to_string(),
1522            statements: vec![Statement::Comment("Do debug accesses".to_string())],
1523        }
1524        .into();
1525
1526        // Check that the elements are correct and in the correct order
1527        let expected_elements: Vec<SequenceElement> = vec![
1528            SequenceBlock {
1529                atomic: None,
1530                info: Some("Define variables and do debug accesses".to_string()),
1531                content: r#"
1532        __var tpWidth = (__traceout & 0x003F0000) >> 16;
1533    "#
1534                .to_string(),
1535                statements: vec![Statement::Definition(Assignment {
1536                    variable: "tpWidth".to_string(),
1537                    expression: Expression::Normal("(__traceout & 0x003F0000) >> 16".to_string()),
1538                })],
1539            }
1540            .into(),
1541            SequenceControl {
1542                conditional_if: Some("__traceout & 0x2".to_string()),
1543                conditional_while: None,
1544                timeout: None,
1545                info: Some("Parallel Trace Port enabled".to_string()),
1546                elements: vec![
1547                    SequenceBlock {
1548                        atomic: None,
1549                        info: None,
1550                        content: r#"
1551            // Do something generic for parallel trace port trace
1552        "#
1553                        .to_string(),
1554                        statements: vec![Statement::Comment(
1555                            "Do something generic for parallel trace port trace".to_string(),
1556                        )],
1557                    }
1558                    .into(),
1559                    SequenceControl {
1560                        conditional_if: Some("tpWidth == 1".to_string()),
1561                        conditional_while: None,
1562                        timeout: None,
1563                        info: Some("Configure device for 1-bit TPIU trace.".to_string()),
1564                        elements: vec![debug_access_block.clone().into()],
1565                        conditional: Some(Expression::Normal("tpWidth == 1".to_string())),
1566                    }
1567                    .into(),
1568                    SequenceControl {
1569                        conditional_if: Some("tpWidth == 2".to_string()),
1570                        conditional_while: None,
1571                        timeout: None,
1572                        info: Some("Configure device for 2-bit TPIU trace.".to_string()),
1573                        elements: vec![debug_access_block.clone().into()],
1574                        conditional: Some(Expression::Normal("tpWidth == 2".to_string())),
1575                    }
1576                    .into(),
1577                    SequenceControl {
1578                        conditional_if: Some("tpWidth == 4".to_string()),
1579                        conditional_while: None,
1580                        timeout: None,
1581                        info: Some("Configure device for 4-bit TPIU trace.".to_string()),
1582                        elements: vec![debug_access_block.clone().into()],
1583                        conditional: Some(Expression::Normal("tpWidth == 4".to_string())),
1584                    }
1585                    .into(),
1586                ],
1587                conditional: Some(Expression::Normal("__traceout & 0x2".to_string())),
1588            }
1589            .into(),
1590        ];
1591
1592        println!("Expected: {:#?}", expected_elements);
1593        println!("Actual: {:#?}", sequence.elements);
1594
1595        assert_eq!(sequence.elements, expected_elements);
1596    }
1597
1598    #[test]
1599    fn basic_sequence_block() {
1600        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
1601<block info="Define condition variales for later use in block elements.">
1602    // Variable definition by __var keyword
1603    __var doIfBlock      = 1;
1604    __var whileCondition = 1;
1605</block>"#;
1606
1607        let document = Document::parse(xml_str).unwrap();
1608        let sequence_node = document.root_element();
1609        let raw_node: RawNode = RawNode(sequence_node);
1610
1611        let block: SequenceBlock = raw_node.0.try_into().unwrap();
1612
1613        assert_eq!(
1614            block.info,
1615            Some("Define condition variales for later use in block elements.".to_string())
1616        );
1617        assert_eq!(block.atomic, None);
1618        assert_eq!(
1619            block.content,
1620            r#"
1621    // Variable definition by __var keyword
1622    __var doIfBlock      = 1;
1623    __var whileCondition = 1;
1624"#
1625        );
1626        assert_eq!(
1627            block.statements,
1628            vec![
1629                Statement::Comment("Variable definition by __var keyword".to_string()),
1630                Statement::Definition(Assignment {
1631                    variable: "doIfBlock".to_string(),
1632                    expression: Expression::Normal("1".to_string())
1633                }),
1634                Statement::Definition(Assignment {
1635                    variable: "whileCondition".to_string(),
1636                    expression: Expression::Normal("1".to_string())
1637                })
1638            ]
1639        );
1640    }
1641
1642    #[test]
1643    fn parse_control_element_if() {
1644        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
1645<control if="doIfBlock">
1646    <block>
1647        // Do debug accesses
1648    </block>
1649</control>"#;
1650
1651        let document = Document::parse(xml_str).unwrap();
1652        let sequence_node = document.root_element();
1653        let raw_node: RawNode = RawNode(sequence_node);
1654
1655        let block: SequenceControl = raw_node.0.try_into().unwrap();
1656
1657        println!("{:#?}", block);
1658        assert_eq!(block.info, None);
1659        assert_eq!(block.conditional_if, Some("doIfBlock".to_string()));
1660        assert_eq!(block.conditional_while, None);
1661        assert_eq!(block.timeout, None);
1662        assert_eq!(
1663            block.elements,
1664            vec![
1665                SequenceBlock {
1666                    atomic: None,
1667                    info: None,
1668                    content: "\n        // Do debug accesses\n    ".to_string(),
1669                    statements: vec![Statement::Comment("Do debug accesses".to_string())]
1670                }
1671                .into()
1672            ]
1673        );
1674    }
1675
1676    #[test]
1677    fn sequence_missing_name_attribute() {
1678        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
1679<sequence>
1680    <block>Write32(0x40000000, 0x1);</block>
1681</sequence>"#;
1682        let document = Document::parse(xml_str).unwrap();
1683        let node = document.root_element();
1684        let result: Result<Sequence, _> = node.try_into();
1685        let err = result.unwrap_err();
1686        let crate::Error::Family(inner) = err else {
1687            panic!("wrong error type")
1688        };
1689        assert_eq!(
1690            inner,
1691            FamilyParseError::MissingAttribute("name".to_string())
1692        );
1693    }
1694
1695    #[test]
1696    fn sequence_element_unknown_tag() {
1697        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
1698<unknown/>"#;
1699        let document = Document::parse(xml_str).unwrap();
1700        let node = document.root_element();
1701        let result: Result<SequenceElement, _> = node.try_into();
1702        let err = result.unwrap_err();
1703        let crate::Error::Family(inner) = err else {
1704            panic!("wrong error type")
1705        };
1706        assert_eq!(
1707            inner,
1708            FamilyParseError::UnknownElementType("unknown".to_string())
1709        );
1710    }
1711
1712    #[test]
1713    fn debugvar_missing_var_prefix() {
1714        use crate::family::Debugvars;
1715        let result = Debugvars::parse_single_debugvar("  myVar = 0x1;");
1716        assert!(matches!(
1717            result,
1718            Err(FamilyParseError::MalformedDebugvar(_))
1719        ));
1720    }
1721
1722    #[test]
1723    fn debugvar_empty_segment() {
1724        use crate::family::Debugvars;
1725        let result = Debugvars::parse_single_debugvar("   ");
1726        assert!(matches!(
1727            result,
1728            Err(FamilyParseError::MalformedDebugvar(_))
1729        ));
1730    }
1731
1732    #[test]
1733    fn parse_control_element_while() {
1734        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
1735<control while="whileCondition" timeout="5000">
1736    <block>
1737        // Execute while "whileCondition" different from '0' with a timeout of 5ms
1738        whileCondition = 0;
1739    </block>
1740</control>"#;
1741
1742        let document = Document::parse(xml_str).unwrap();
1743        let sequence_node = document.root_element();
1744        let raw_node: RawNode = RawNode(sequence_node);
1745
1746        let block: SequenceControl = raw_node.0.try_into().unwrap();
1747
1748        println!("{:#?}", block);
1749        assert_eq!(block.info, None);
1750        assert_eq!(block.conditional_if, None);
1751        assert_eq!(block.conditional_while, Some("whileCondition".to_string()));
1752        assert_eq!(block.timeout, Some(5000));
1753        assert_eq!(block.elements, vec![
1754            SequenceBlock{
1755                atomic: None,
1756                info: None,
1757                content: r#"
1758        // Execute while "whileCondition" different from '0' with a timeout of 5ms
1759        whileCondition = 0;
1760    "#.to_string(),
1761                statements: vec![
1762                    Statement::Comment("Execute while \"whileCondition\" different from '0' with a timeout of 5ms".to_string()),
1763                    Statement::Assignment(Assignment {
1764                        variable: "whileCondition".to_string(),
1765                        expression: Expression::Normal("0".to_string())
1766                    })
1767                ]
1768            }.into()
1769        ]);
1770    }
1771
1772    #[test]
1773    fn parse_family_with_description() {
1774        // Family with a description element
1775        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
1776<family Dfamily="STM32F1" Dvendor="STMicroelectronics:13">
1777    <description>STM32F1 Arm Cortex-M3 microcontroller series</description>
1778    <debugvars></debugvars>
1779    <sequences/>
1780</family>"#;
1781        let document = Document::parse(xml_str).unwrap();
1782        let family: crate::family::Family = serde_roxmltree::from_doc(&document).unwrap();
1783        assert_eq!(
1784            family.description,
1785            vec!["STM32F1 Arm Cortex-M3 microcontroller series".to_string()]
1786        );
1787        assert_eq!(family.processor.len(), 0);
1788    }
1789
1790    #[test]
1791    fn parse_family_processor() {
1792        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
1793<family Dfamily="LPC" Dvendor="NXP:11">
1794    <processor Pname="Cortex-M3" Dcore="Cortex-M3" Dfpu="NO_FPU" Dmpu="NO_MPU" Dclock="120000000"/>
1795    <debugvars></debugvars>
1796    <sequences/>
1797</family>"#;
1798        let document = Document::parse(xml_str).unwrap();
1799        let family: crate::family::Family = serde_roxmltree::from_doc(&document).unwrap();
1800        assert_eq!(family.processor.len(), 1);
1801        let p = &family.processor[0];
1802        assert_eq!(p.pname, Some("Cortex-M3".to_string()));
1803        assert_eq!(p.dcore, Some("Cortex-M3".to_string()));
1804        assert_eq!(p.dfpu, Some("NO_FPU".to_string()));
1805        assert_eq!(p.dclock, Some(120_000_000));
1806    }
1807
1808    #[test]
1809    fn parse_family_algorithm() {
1810        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
1811<family Dfamily="STM32F1" Dvendor="STMicroelectronics:13">
1812    <algorithm name="Flash/STM32F1xx_128.FLM" start="0x08000000" size="0x00020000"
1813               RAMstart="0x20000000" RAMsize="0x00001000" default="true"/>
1814    <debugvars></debugvars>
1815    <sequences/>
1816</family>"#;
1817        let document = Document::parse(xml_str).unwrap();
1818        let family: crate::family::Family = serde_roxmltree::from_doc(&document).unwrap();
1819        assert_eq!(family.algorithm.len(), 1);
1820        let a = &family.algorithm[0];
1821        assert_eq!(a.name, "Flash/STM32F1xx_128.FLM");
1822        assert_eq!(a.start, Some("0x08000000".to_string()));
1823        assert_eq!(a.size, Some("0x00020000".to_string()));
1824        assert_eq!(a.ram_start, Some("0x20000000".to_string()));
1825        assert_eq!(a.ram_size, Some("0x00001000".to_string()));
1826        assert_eq!(a.default, Some(true));
1827        assert_eq!(a.device_index, None);
1828        assert_eq!(a.parameter, None);
1829        assert_eq!(a.endian, "Little-endian");
1830    }
1831
1832    #[test]
1833    fn parse_family_memory() {
1834        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
1835<family Dfamily="STM32F1" Dvendor="STMicroelectronics:13">
1836    <memory name="IROM1" access="rx" start="0x08000000" size="0x00020000" startup="true" default="true"/>
1837    <memory name="IRAM1" access="rw" start="0x20000000" size="0x00005000" uninit="true" default="true"/>
1838    <debugvars></debugvars>
1839    <sequences/>
1840</family>"#;
1841        let document = Document::parse(xml_str).unwrap();
1842        let family: crate::family::Family = serde_roxmltree::from_doc(&document).unwrap();
1843        assert_eq!(family.memory.len(), 2);
1844        let rom = &family.memory[0];
1845        assert_eq!(rom.name, Some("IROM1".to_string()));
1846        assert_eq!(rom.access, Some("rx".to_string()));
1847        assert_eq!(rom.start, "0x08000000");
1848        assert_eq!(rom.startup, Some(true));
1849        assert_eq!(rom.default, Some(true));
1850        let ram = &family.memory[1];
1851        assert_eq!(ram.uninit, Some(true));
1852    }
1853
1854    #[test]
1855    fn parse_family_book() {
1856        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
1857<family Dfamily="STM32F1" Dvendor="STMicroelectronics:13">
1858    <book name="Docs/DM00031936.pdf" title="STM32F1 Reference Manual"/>
1859    <debugvars></debugvars>
1860    <sequences/>
1861</family>"#;
1862        let document = Document::parse(xml_str).unwrap();
1863        let family: crate::family::Family = serde_roxmltree::from_doc(&document).unwrap();
1864        assert_eq!(family.book.len(), 1);
1865        assert_eq!(family.book[0].name, "Docs/DM00031936.pdf");
1866        assert_eq!(family.book[0].title, "STM32F1 Reference Manual");
1867        assert_eq!(family.book[0].public, None);
1868    }
1869
1870    #[test]
1871    fn parse_family_feature() {
1872        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
1873<family Dfamily="STM32F1" Dvendor="STMicroelectronics:13">
1874    <feature type="UART" n="3" name="Universal Asynchronous Receiver/Transmitter"/>
1875    <feature type="ADC" n="1" m="12"/>
1876    <debugvars></debugvars>
1877    <sequences/>
1878</family>"#;
1879        let document = Document::parse(xml_str).unwrap();
1880        let family: crate::family::Family = serde_roxmltree::from_doc(&document).unwrap();
1881        assert_eq!(family.feature.len(), 2);
1882        assert_eq!(family.feature[0].feature_type, "UART");
1883        assert_eq!(family.feature[0].n, Some("3".to_string()));
1884        assert_eq!(
1885            family.feature[0].name,
1886            Some("Universal Asynchronous Receiver/Transmitter".to_string())
1887        );
1888        assert_eq!(family.feature[1].m, Some("12".to_string()));
1889    }
1890
1891    #[test]
1892    fn parse_family_feature_count() {
1893        // Deprecated `count` attribute on `feature`, kept for backwards compatibility
1894        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
1895<family Dfamily="STM32F1" Dvendor="STMicroelectronics:13">
1896    <feature type="UART" n="3" count="2"/>
1897    <feature type="ADC" n="1" m="12"/>
1898    <debugvars></debugvars>
1899    <sequences/>
1900</family>"#;
1901        let document = Document::parse(xml_str).unwrap();
1902        let family: crate::family::Family = serde_roxmltree::from_doc(&document).unwrap();
1903        assert_eq!(family.feature[0].count, Some(2));
1904        assert_eq!(family.feature[1].count, None);
1905    }
1906
1907    #[test]
1908    fn parse_family_debug_and_debugconfig() {
1909        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
1910<family Dfamily="STM32F1" Dvendor="STMicroelectronics:13">
1911    <debug svd="SVD/STM32F103xx.svd" __dp="0" __ap="0"/>
1912    <debugconfig default="swd" clock="5000000" swj="true"/>
1913    <debugvars></debugvars>
1914    <sequences/>
1915</family>"#;
1916        let document = Document::parse(xml_str).unwrap();
1917        let family: crate::family::Family = serde_roxmltree::from_doc(&document).unwrap();
1918        assert_eq!(family.debug.len(), 1);
1919        assert_eq!(family.debug[0].svd, Some("SVD/STM32F103xx.svd".to_string()));
1920        assert_eq!(family.debug[0].dp, Some(0));
1921        assert_eq!(family.debug[0].ap, Some(0));
1922        let dc = family.debugconfig.as_ref().unwrap();
1923        assert_eq!(dc.default, Some("swd".to_string()));
1924        assert_eq!(dc.clock, Some(5_000_000));
1925        assert_eq!(dc.swj, Some(true));
1926    }
1927
1928    #[test]
1929    fn parse_family_debugport() {
1930        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
1931<family Dfamily="STM32F1" Dvendor="STMicroelectronics:13">
1932    <debugport __dp="0">
1933        <swd/>
1934        <jtag tapindex="0"/>
1935    </debugport>
1936    <debugvars></debugvars>
1937    <sequences/>
1938</family>"#;
1939        let document = Document::parse(xml_str).unwrap();
1940        let family: crate::family::Family = serde_roxmltree::from_doc(&document).unwrap();
1941        assert_eq!(family.debugport.len(), 1);
1942        let dp = &family.debugport[0];
1943        assert_eq!(dp.dp, Some(0));
1944        assert!(dp.swd.is_some());
1945        assert!(dp.jtag.is_some());
1946        assert_eq!(dp.jtag.as_ref().unwrap().tapindex, Some(0));
1947    }
1948
1949    #[test]
1950    fn parse_family_access_ports() {
1951        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
1952<family Dfamily="STM32F1" Dvendor="STMicroelectronics:13">
1953    <accessportV1 __apid="0" __dp="0" index="0"/>
1954    <accessportV2 __apid="1" __dp="0" address="0xE0041000"/>
1955    <debugvars></debugvars>
1956    <sequences/>
1957</family>"#;
1958        let document = Document::parse(xml_str).unwrap();
1959        let family: crate::family::Family = serde_roxmltree::from_doc(&document).unwrap();
1960        assert_eq!(family.access_port_v1.len(), 1);
1961        assert_eq!(family.access_port_v1[0].apid, 0);
1962        assert_eq!(family.access_port_v1[0].dp, Some(0));
1963        assert_eq!(family.access_port_v1[0].index, 0);
1964        assert_eq!(family.access_port_v2.len(), 1);
1965        assert_eq!(family.access_port_v2[0].apid, 1);
1966        assert_eq!(family.access_port_v2[0].address, "0xE0041000");
1967    }
1968
1969    #[test]
1970    fn parse_family_compile() {
1971        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
1972<family Dfamily="STM32F1" Dvendor="STMicroelectronics:13">
1973    <compile header="Include/stm32f1xx.h" define="STM32F1"/>
1974    <debugvars></debugvars>
1975    <sequences/>
1976</family>"#;
1977        let document = Document::parse(xml_str).unwrap();
1978        let family: crate::family::Family = serde_roxmltree::from_doc(&document).unwrap();
1979        assert_eq!(family.compile.len(), 1);
1980        assert_eq!(
1981            family.compile[0].header,
1982            Some("Include/stm32f1xx.h".to_string())
1983        );
1984        assert_eq!(family.compile[0].define, Some("STM32F1".to_string()));
1985    }
1986
1987    #[test]
1988    fn parse_family_flashinfo() {
1989        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
1990<family Dfamily="STM32F1" Dvendor="STMicroelectronics:13">
1991    <flashinfo name="Flash" start="0x08000000" pagesize="0x400" blankval="0xFF">
1992        <block count="128" size="0x400"/>
1993    </flashinfo>
1994    <debugvars></debugvars>
1995    <sequences/>
1996</family>"#;
1997        let document = Document::parse(xml_str).unwrap();
1998        let family: crate::family::Family = serde_roxmltree::from_doc(&document).unwrap();
1999        assert_eq!(family.flashinfo_raw.len(), 1);
2000        let flashinfo = parse_flashinfo(&family.flashinfo_raw).unwrap();
2001        assert_eq!(flashinfo.len(), 1);
2002        let fi = &flashinfo[0];
2003        assert_eq!(fi.name, "Flash");
2004        assert_eq!(fi.start, "0x08000000");
2005        assert_eq!(fi.pagesize, "0x400");
2006        assert_eq!(fi.blankval, Some("0xFF".to_string()));
2007        assert_eq!(
2008            fi.elements,
2009            vec![FlashInfoElement::Block(FlashBlock {
2010                count: 128,
2011                size: "0x400".to_string(),
2012                arg: None,
2013            })]
2014        );
2015    }
2016
2017    #[test]
2018    fn parse_family_flashinfo_interleaved_order() {
2019        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
2020<family Dfamily="STM32F1" Dvendor="STMicroelectronics:13">
2021    <flashinfo name="Flash" start="0x08000000" pagesize="0x400" blankval="0xFF">
2022        <gap size="0x10"/>
2023        <block count="128" size="0x400"/>
2024        <gap size="0x20"/>
2025    </flashinfo>
2026    <debugvars></debugvars>
2027    <sequences/>
2028</family>"#;
2029        let document = Document::parse(xml_str).unwrap();
2030        let family: crate::family::Family = serde_roxmltree::from_doc(&document).unwrap();
2031        let flashinfo = parse_flashinfo(&family.flashinfo_raw).unwrap();
2032        assert_eq!(flashinfo.len(), 1);
2033        assert_eq!(
2034            flashinfo[0].elements,
2035            vec![
2036                FlashInfoElement::Gap(FlashGap {
2037                    size: "0x10".to_string(),
2038                }),
2039                FlashInfoElement::Block(FlashBlock {
2040                    count: 128,
2041                    size: "0x400".to_string(),
2042                    arg: None,
2043                }),
2044                FlashInfoElement::Gap(FlashGap {
2045                    size: "0x20".to_string(),
2046                }),
2047            ]
2048        );
2049    }
2050
2051    #[test]
2052    fn parse_family_trace() {
2053        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
2054<family Dfamily="STM32F1" Dvendor="STMicroelectronics:13">
2055    <trace Pname="Core0">
2056        <serialwire/>
2057        <traceport width="4"/>
2058        <tracebuffer start="0xE0041000" size="0x1000"/>
2059    </trace>
2060    <debugvars></debugvars>
2061    <sequences/>
2062</family>"#;
2063        let document = Document::parse(xml_str).unwrap();
2064        let family: crate::family::Family = serde_roxmltree::from_doc(&document).unwrap();
2065        assert_eq!(family.trace.len(), 1);
2066        let trace = &family.trace[0];
2067        assert_eq!(trace.pname, Some("Core0".to_string()));
2068        assert_eq!(trace.serialwire.len(), 1);
2069        assert_eq!(trace.traceport.len(), 1);
2070        assert_eq!(trace.traceport[0].width, Some(4));
2071        assert_eq!(trace.tracebuffer.len(), 1);
2072        assert_eq!(trace.tracebuffer[0].start, Some("0xE0041000".to_string()));
2073        assert_eq!(trace.tracebuffer[0].size, Some("0x1000".to_string()));
2074    }
2075
2076    #[test]
2077    fn parse_family_environment() {
2078        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
2079<family Dfamily="STM32F1" Dvendor="STMicroelectronics:13">
2080    <environment name="uv" Pname="Core0"/>
2081    <debugvars></debugvars>
2082    <sequences/>
2083</family>"#;
2084        let document = Document::parse(xml_str).unwrap();
2085        let family: crate::family::Family = serde_roxmltree::from_doc(&document).unwrap();
2086        assert_eq!(family.environment.len(), 1);
2087        assert_eq!(family.environment[0].name, "uv");
2088        assert_eq!(family.environment[0].pname, Some("Core0".to_string()));
2089    }
2090
2091    #[test]
2092    fn parse_device_basic() {
2093        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
2094<device Dname="PIC32CM1216PL10028">
2095    <processor Dcore="Cortex-M0+" Dendian="Little-endian" Dmpu="NO_MPU" Dfpu="NO_FPU"
2096               Ddsp="NO_DSP" Dtz="NO_TZ" Dmve="NO_MVE" Dclock="24000000" DcoreVersion="r0p0"/>
2097    <memory name="FLASH" start="0x0C000000" size="0x20000" access="rx" default="1" startup="1"/>
2098    <memory name="HSRAM" start="0x20000000" size="0x4000" default="1" access="rwx"/>
2099</device>"#;
2100        let document = Document::parse(xml_str).unwrap();
2101        let device: crate::family::Device = serde_roxmltree::from_doc(&document).unwrap();
2102        assert_eq!(device.device_name, "PIC32CM1216PL10028");
2103        assert_eq!(device.processor.len(), 1);
2104        assert_eq!(device.processor[0].dcore, Some("Cortex-M0+".to_string()));
2105        assert_eq!(device.processor[0].dclock, Some(24000000));
2106        assert_eq!(device.memory.len(), 2);
2107        assert_eq!(device.memory[0].name, Some("FLASH".to_string()));
2108        assert_eq!(device.memory[0].start, "0x0C000000");
2109        assert_eq!(device.memory[1].name, Some("HSRAM".to_string()));
2110        assert_eq!(device.variants.len(), 0);
2111    }
2112
2113    #[test]
2114    fn parse_device_with_variant() {
2115        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
2116<device Dname="LPC1768">
2117    <processor Dcore="Cortex-M3" Dclock="100000000"/>
2118    <variant Dvariant="LPC1768FBD100">
2119        <memory name="FLASH" start="0x00000000" size="0x80000" access="rx"/>
2120    </variant>
2121    <variant Dvariant="LPC1768FET100">
2122        <processor Dcore="Cortex-M3" Dclock="120000000"/>
2123    </variant>
2124</device>"#;
2125        let document = Document::parse(xml_str).unwrap();
2126        let device: crate::family::Device = serde_roxmltree::from_doc(&document).unwrap();
2127        assert_eq!(device.device_name, "LPC1768");
2128        assert_eq!(device.variants.len(), 2);
2129        assert_eq!(device.variants[0].variant_name, "LPC1768FBD100");
2130        assert_eq!(device.variants[0].memory.len(), 1);
2131        assert_eq!(device.variants[1].variant_name, "LPC1768FET100");
2132        assert_eq!(device.variants[1].processor[0].dclock, Some(120000000));
2133    }
2134
2135    #[test]
2136    fn parse_subfamily_with_devices() {
2137        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
2138<subFamily DsubFamily="LPC176x">
2139    <processor Dcore="Cortex-M3"/>
2140    <device Dname="LPC1768">
2141        <processor Dclock="100000000"/>
2142        <memory name="FLASH" start="0x00000000" size="0x80000" access="rx"/>
2143    </device>
2144    <device Dname="LPC1766">
2145        <processor Dclock="100000000"/>
2146        <memory name="FLASH" start="0x00000000" size="0x40000" access="rx"/>
2147    </device>
2148</subFamily>"#;
2149        let document = Document::parse(xml_str).unwrap();
2150        let sf: crate::family::SubFamily = serde_roxmltree::from_doc(&document).unwrap();
2151        assert_eq!(sf.sub_family_name, "LPC176x");
2152        assert_eq!(sf.processor.len(), 1);
2153        assert_eq!(sf.processor[0].dcore, Some("Cortex-M3".to_string()));
2154        assert_eq!(sf.devices.len(), 2);
2155        assert_eq!(sf.devices[0].device_name, "LPC1768");
2156        assert_eq!(sf.devices[0].memory[0].size, "0x80000");
2157        assert_eq!(sf.devices[1].device_name, "LPC1766");
2158    }
2159
2160    #[test]
2161    fn parse_family_with_direct_devices() {
2162        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
2163<family Dfamily="PIC32CM-PL" Dvendor="Microchip:3">
2164    <debugvars configfile="debug.dbgconf" version="1.0.0">__var myVar = 0x1;</debugvars>
2165    <sequences/>
2166    <device Dname="PIC32CM1216PL10028">
2167        <processor Dcore="Cortex-M0+" Dclock="24000000"/>
2168        <debugconfig default="swd" clock="2000000"/>
2169        <compile header="pic32cm1216pl/include/pic32c.h" define="__PIC32CM1216PL10028__"/>
2170        <memory name="FLASH" start="0x0C000000" size="0x20000" access="rx"/>
2171        <algorithm name="keil/Flash/PIC32CM-PL_FLASH_128.FLM" start="0x0C000000" size="0x20000"
2172                   RAMstart="0x20000000" RAMsize="0x2000" default="1" style="Keil"/>
2173    </device>
2174    <device Dname="PIC32CM2532PL10028">
2175        <processor Dcore="Cortex-M0+" Dclock="24000000"/>
2176        <memory name="FLASH" start="0x0C000000" size="0x40000" access="rx"/>
2177    </device>
2178</family>"#;
2179        let document = Document::parse(xml_str).unwrap();
2180        let family: crate::family::Family = serde_roxmltree::from_doc(&document).unwrap();
2181        assert_eq!(family.device_family, "PIC32CM-PL");
2182        assert_eq!(family.devices.len(), 2);
2183        assert_eq!(family.sub_families.len(), 0);
2184
2185        let d0 = &family.devices[0];
2186        assert_eq!(d0.device_name, "PIC32CM1216PL10028");
2187        assert_eq!(d0.processor[0].dcore, Some("Cortex-M0+".to_string()));
2188        assert_eq!(
2189            d0.debugconfig.as_ref().unwrap().default,
2190            Some("swd".to_string())
2191        );
2192        assert_eq!(
2193            d0.compile[0].header,
2194            Some("pic32cm1216pl/include/pic32c.h".to_string())
2195        );
2196        assert_eq!(d0.memory[0].name, Some("FLASH".to_string()));
2197        assert_eq!(d0.algorithm[0].name, "keil/Flash/PIC32CM-PL_FLASH_128.FLM");
2198        assert_eq!(d0.algorithm[0].default, Some(true));
2199
2200        let d1 = &family.devices[1];
2201        assert_eq!(d1.device_name, "PIC32CM2532PL10028");
2202        assert_eq!(d1.memory[0].size, "0x40000");
2203    }
2204
2205    #[test]
2206    fn parse_deprecated_element() {
2207        // `deprecated` is a child element (xs:date), not an attribute, and may appear at
2208        // the family, subFamily, device and variant levels (DevicePropertiesGroup).
2209        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
2210<family Dfamily="STM32F1" Dvendor="STMicroelectronics:13">
2211    <deprecated>2020-01-01</deprecated>
2212    <debugvars></debugvars>
2213    <sequences/>
2214    <subFamily DsubFamily="STM32F103">
2215        <deprecated>2020-02-02</deprecated>
2216    </subFamily>
2217    <device Dname="STM32F103C8">
2218        <deprecated>2020-03-03</deprecated>
2219        <variant Dvariant="STM32F103C8Tx">
2220            <deprecated>2020-04-04</deprecated>
2221        </variant>
2222    </device>
2223</family>"#;
2224        let document = Document::parse(xml_str).unwrap();
2225        let family: crate::family::Family = serde_roxmltree::from_doc(&document).unwrap();
2226        assert_eq!(family.deprecated, Some("2020-01-01".to_string()));
2227        assert_eq!(
2228            family.sub_families[0].deprecated,
2229            Some("2020-02-02".to_string())
2230        );
2231        assert_eq!(family.devices[0].deprecated, Some("2020-03-03".to_string()));
2232        assert_eq!(
2233            family.devices[0].variants[0].deprecated,
2234            Some("2020-04-04".to_string())
2235        );
2236    }
2237
2238    #[test]
2239    fn parse_variant_debugvars_and_sequences() {
2240        // `debugvars` and `sequences` are valid at the variant level too, mirroring
2241        // Device and SubFamily.
2242        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
2243<device Dname="LPC1768">
2244    <variant Dvariant="LPC1768FBD100">
2245        <debugvars configfile="debug.dbgconf" version="1.0.0">__var myVar = 0x1;</debugvars>
2246        <sequences/>
2247    </variant>
2248</device>"#;
2249        let document = Document::parse(xml_str).unwrap();
2250        let mut device: crate::family::Device = serde_roxmltree::from_doc(&document).unwrap();
2251        assert_eq!(device.variants.len(), 1);
2252        device.variants[0].debugvars =
2253            crate::family::merge_debugvars(&device.variants[0].debugvars_raw).unwrap();
2254        assert_eq!(
2255            device.variants[0].debugvars.configfile,
2256            Some("debug.dbgconf".to_string())
2257        );
2258        assert_eq!(
2259            device.variants[0].debugvars.version,
2260            Some("1.0.0".to_string())
2261        );
2262    }
2263
2264    #[test]
2265    fn parse_family_debugvars_multiple_siblings() {
2266        // `PACK.xsd`'s `DevicePropertiesGroup` models `<debugvars>` as part of an unbounded
2267        // `xs:choice`, so more than one `<debugvars>` sibling is legal and must be merged.
2268        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
2269<family Dfamily="STM32F1" Dvendor="STMicroelectronics:13">
2270    <debugvars configfile="debug.dbgconf" version="1.0.0">__var myVar = 0x1;</debugvars>
2271    <debugvars>__var otherVar = 0x2;</debugvars>
2272    <sequences/>
2273</family>"#;
2274        let document = Document::parse(xml_str).unwrap();
2275        let mut family: crate::family::Family = serde_roxmltree::from_doc(&document).unwrap();
2276        assert_eq!(family.debugvars_raw.len(), 2);
2277
2278        family.debugvars = crate::family::merge_debugvars(&family.debugvars_raw).unwrap();
2279        assert_eq!(
2280            family.debugvars.configfile,
2281            Some("debug.dbgconf".to_string())
2282        );
2283        assert_eq!(family.debugvars.version, Some("1.0.0".to_string()));
2284
2285        family.debugvars.parse_debugvars();
2286        let parsed = family.debugvars.parsed_debugvars.unwrap();
2287        assert_eq!(parsed.get("myVar"), Some(&1));
2288        assert_eq!(parsed.get("otherVar"), Some(&2));
2289    }
2290
2291    #[test]
2292    fn parse_family_sequences_multiple_siblings() {
2293        // `PACK.xsd`'s `DevicePropertiesGroup` models `<sequences>` as part of an unbounded
2294        // `xs:choice`, so more than one `<sequences>` sibling is legal and must be merged,
2295        // preserving the document order of the `<sequence>` children across siblings.
2296        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
2297<family Dfamily="STM32F1" Dvendor="STMicroelectronics:13">
2298    <debugvars></debugvars>
2299    <sequences traceSetup="full">
2300        <sequence name="SeqA">
2301            <block>Sequence("A");</block>
2302        </sequence>
2303    </sequences>
2304    <sequences>
2305        <sequence name="SeqB">
2306            <block>Sequence("B");</block>
2307        </sequence>
2308    </sequences>
2309</family>"#;
2310        let document = Document::parse(xml_str).unwrap();
2311        let mut family: crate::family::Family = serde_roxmltree::from_doc(&document).unwrap();
2312        assert_eq!(family.sequences_raw.len(), 2);
2313
2314        family.sequences = crate::family::merge_sequences(&family.sequences_raw).unwrap();
2315        assert_eq!(family.sequences.trace_setup, Some(TraceSetup::Full));
2316        assert_eq!(family.sequences.raw_nodes.len(), 2);
2317
2318        family.sequences.parse_sequences().unwrap();
2319        assert_eq!(family.sequences.sequences.len(), 2);
2320        assert_eq!(family.sequences.sequences[0].name, "SeqA");
2321        assert_eq!(family.sequences.sequences[1].name, "SeqB");
2322    }
2323}