Skip to content

Commit c390d0c

Browse files
committed
extract enums
1 parent 25985dc commit c390d0c

File tree

4 files changed

+174
-1
lines changed

4 files changed

+174
-1
lines changed

src/cli.rs

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

55
use svdtools::{
66
convert::convert_cli,
7+
enum_extract::enum_extract,
78
html::html_cli,
89
html::htmlcompare_cli,
910
info,
@@ -134,6 +135,16 @@ enum Command {
134135
/// Describe requested information
135136
request: String,
136137
},
138+
/// Makes patch file with enums extracted from SVD
139+
ExtractEnums {
140+
/// Path to input file
141+
in_path: PathBuf,
142+
/// Format of input file (XML, JSON or YAML)
143+
#[clap(long = "input-format")]
144+
input_format: Option<convert_cli::InputFormat>,
145+
/// Path to output file
146+
out_path: PathBuf,
147+
},
137148
}
138149

139150
impl Command {
@@ -226,6 +237,22 @@ impl Command {
226237
let response = request.process(&device)?;
227238
print!("{response}")
228239
}
240+
Self::ExtractEnums {
241+
in_path,
242+
input_format,
243+
out_path,
244+
} => {
245+
let device = convert_cli::open_svd(
246+
in_path,
247+
*input_format,
248+
convert_cli::ParserConfig::default(),
249+
)?;
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/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)