Skip to content

Commit f7b9f74

Browse files
committed
extract enums
1 parent 59e01eb commit f7b9f74

File tree

5 files changed

+179
-3
lines changed

5 files changed

+179
-3
lines changed

src/cli.rs

+27
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
use anyhow::{Ok, Result};
22
use clap::Parser;
33
use std::{fs::File, io::Write, path::PathBuf, str::FromStr};
4+
use svd_rs::ValidateLevel;
45

56
use svdtools::{
67
convert::convert_cli,
8+
enum_extract::enum_extract,
79
html::html_cli,
810
html::htmlcompare_cli,
911
info,
@@ -134,6 +136,16 @@ enum Command {
134136
/// Describe requested information
135137
request: String,
136138
},
139+
/// Makes patch file with enums extracted from SVD
140+
ExtractEnums {
141+
/// Path to input file
142+
in_path: PathBuf,
143+
/// Format of input file (XML, JSON or YAML)
144+
#[clap(long = "input-format")]
145+
input_format: Option<convert_cli::InputFormat>,
146+
/// Path to output file
147+
out_path: PathBuf,
148+
},
137149
}
138150

139151
impl Command {
@@ -200,6 +212,7 @@ impl Command {
200212
expand: *expand,
201213
expand_properties: *expand_properties,
202214
ignore_enums: *ignore_enums,
215+
validate_level: ValidateLevel::Disabled,
203216
},
204217
format_config.as_ref().map(|p| p.as_path()),
205218
)?,
@@ -226,6 +239,20 @@ impl Command {
226239
let response = request.process(&device)?;
227240
print!("{response}")
228241
}
242+
Self::ExtractEnums {
243+
in_path,
244+
input_format,
245+
out_path,
246+
} => {
247+
let mut cfg = convert_cli::ParserConfig::default();
248+
cfg.validate_level = ValidateLevel::Disabled;
249+
let device = convert_cli::open_svd(in_path, *input_format, cfg)?;
250+
let yml = enum_extract(&device);
251+
let mut out_str = String::new();
252+
let mut emitter = yaml_rust::YamlEmitter::new(&mut out_str);
253+
emitter.dump(&yml).unwrap();
254+
File::create(out_path)?.write_all(out_str.as_bytes())?;
255+
}
229256
}
230257
Ok(())
231258
}

src/convert/convert_cli.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use anyhow::{anyhow, Result};
22
use std::io::{Read, Write};
33
use std::str::FromStr;
44
use std::{fs::File, path::Path};
5-
use svd_rs::Device;
5+
use svd_rs::{Device, ValidateLevel};
66

77
use crate::get_encoder_config;
88
pub use crate::ConfigFormat;
@@ -52,6 +52,7 @@ pub struct ParserConfig {
5252
pub expand: bool,
5353
pub expand_properties: bool,
5454
pub ignore_enums: bool,
55+
pub validate_level: ValidateLevel,
5556
}
5657

5758
pub fn open_svd(
@@ -73,7 +74,9 @@ pub fn open_svd(
7374
let mut device = match input_format {
7475
InputFormat::Xml => svd_parser::parse_with_config(
7576
&input,
76-
&svd_parser::Config::default().ignore_enums(parser_config.ignore_enums),
77+
&svd_parser::Config::default()
78+
.ignore_enums(parser_config.ignore_enums)
79+
.validate_level(parser_config.validate_level),
7780
)?,
7881
InputFormat::Yaml => serde_yaml::from_str(&input)?,
7982
InputFormat::Json => serde_json::from_str(&input)?,

src/enum_extract/mod.rs

+144
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
use crate::patch::ToYaml;
2+
use svd_rs::EnumeratedValues;
3+
use yaml_rust::yaml::{self, Yaml};
4+
5+
pub trait HasEnums {
6+
fn has_enums(&self) -> bool;
7+
}
8+
9+
impl HasEnums for svd_rs::Field {
10+
fn has_enums(&self) -> bool {
11+
!self.enumerated_values.is_empty()
12+
}
13+
}
14+
15+
impl HasEnums for svd_rs::Register {
16+
fn has_enums(&self) -> bool {
17+
if let Some(fields) = self.fields.as_ref() {
18+
for f in fields {
19+
if f.has_enums() {
20+
return true;
21+
}
22+
}
23+
}
24+
false
25+
}
26+
}
27+
28+
impl HasEnums for svd_rs::RegisterCluster {
29+
fn has_enums(&self) -> bool {
30+
match self {
31+
svd_rs::RegisterCluster::Cluster(c) => c.has_enums(),
32+
svd_rs::RegisterCluster::Register(r) => r.has_enums(),
33+
}
34+
}
35+
}
36+
37+
impl HasEnums for svd_rs::Cluster {
38+
fn has_enums(&self) -> bool {
39+
for rc in &self.children {
40+
if rc.has_enums() {
41+
return true;
42+
}
43+
}
44+
false
45+
}
46+
}
47+
48+
impl HasEnums for svd_rs::Peripheral {
49+
fn has_enums(&self) -> bool {
50+
if let Some(regs) = self.registers.as_ref() {
51+
for rc in regs {
52+
if rc.has_enums() {
53+
return true;
54+
}
55+
}
56+
}
57+
false
58+
}
59+
}
60+
61+
fn evs_to_hash(evs: &EnumeratedValues) -> yaml::Hash {
62+
let mut hash = yaml::Hash::with_capacity(evs.values.len());
63+
if let Some(n) = evs.name.as_ref() {
64+
hash.insert("_name".to_yaml(), n.to_yaml());
65+
}
66+
if let Some(d) = evs.derived_from.as_ref() {
67+
hash.insert("_derivedFrom".to_yaml(), d.to_yaml());
68+
} else {
69+
for ev in &evs.values {
70+
let val = if let Some(val) = ev.value {
71+
Yaml::Integer(val as _)
72+
} else if ev.is_default() {
73+
Yaml::Integer(-1)
74+
} else {
75+
panic!("EnumeratedValue without value");
76+
};
77+
hash.insert(
78+
ev.name.to_yaml(),
79+
Yaml::Array(vec![val, ev.description.as_deref().unwrap_or("").to_yaml()]),
80+
);
81+
}
82+
}
83+
hash
84+
}
85+
86+
fn rc_enum_extact(regs: &[svd_rs::RegisterCluster]) -> Yaml {
87+
let mut phash = yaml::Hash::new();
88+
let mut pchash = yaml::Hash::new();
89+
for rc in regs {
90+
if rc.has_enums() {
91+
match rc {
92+
svd_rs::RegisterCluster::Cluster(c) => {
93+
pchash.insert(c.name.to_yaml(), rc_enum_extact(&c.children));
94+
}
95+
svd_rs::RegisterCluster::Register(r) => {
96+
let mut rhash = yaml::Hash::new();
97+
for f in r.fields() {
98+
if f.has_enums() {
99+
let mut fhash = yaml::Hash::with_capacity(f.enumerated_values.len());
100+
for evs in &f.enumerated_values {
101+
match evs.usage {
102+
Some(svd_rs::Usage::Read) => {
103+
fhash.insert(
104+
"_read".to_yaml(),
105+
Yaml::Hash(evs_to_hash(evs)),
106+
);
107+
}
108+
Some(svd_rs::Usage::Write) => {
109+
fhash.insert(
110+
"_write".to_yaml(),
111+
Yaml::Hash(evs_to_hash(evs)),
112+
);
113+
}
114+
_ => {
115+
assert_eq!(f.enumerated_values.len(), 1);
116+
fhash.extend(evs_to_hash(evs));
117+
}
118+
}
119+
}
120+
rhash.insert(f.name.to_yaml(), Yaml::Hash(fhash));
121+
}
122+
}
123+
phash.insert(r.name.to_yaml(), Yaml::Hash(rhash));
124+
}
125+
}
126+
}
127+
}
128+
if !pchash.is_empty() {
129+
phash.insert("_clusters".to_yaml(), Yaml::Hash(pchash));
130+
}
131+
Yaml::Hash(phash)
132+
}
133+
134+
pub fn enum_extract(device: &svd_rs::Device) -> Yaml {
135+
let mut hash = yaml::Hash::new();
136+
for p in &device.peripherals {
137+
if let Some(regs) = p.registers.as_ref() {
138+
if p.has_enums() {
139+
hash.insert(p.name.to_yaml(), rc_enum_extact(regs));
140+
}
141+
}
142+
}
143+
Yaml::Hash(hash)
144+
}

src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::{fs::File, path::Path, str::FromStr};
44

55
pub mod common;
66
pub mod convert;
7+
pub mod enum_extract;
78
pub mod html;
89
pub mod info;
910
pub mod interrupts;

src/patch/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ mod iterators;
3232
mod peripheral;
3333
mod register;
3434
mod yaml_ext;
35-
use yaml_ext::{AsType, GetVal, ToYaml};
35+
pub(crate) use yaml_ext::ToYaml;
36+
use yaml_ext::{AsType, GetVal};
3637

3738
use crate::get_encoder_config;
3839

0 commit comments

Comments
 (0)