diff --git a/CHANGELOG.md b/CHANGELOG.md
index 170abd96..d72e4aa3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
+- Add support of reading SVD from YAML or JSON files instead of XML
+- Fix ValidateLevel usage in lib.rs
+- Use `svd-parser` v0.12.1
+
## [v0.20.0] - 2021-12-07
### Fixed
diff --git a/Cargo.toml b/Cargo.toml
index ec7c725a..d31f0b9f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -45,11 +45,17 @@ quote = "1.0"
proc-macro2 = "1.0"
anyhow = "1.0"
thiserror = "1.0"
+serde_yaml = "0.8.21"
+serde_json = "1.0.72"
[dependencies.svd-parser]
features = ["derive-from"]
version = "0.12"
+[dependencies.svd-rs]
+features = ["serde"]
+version = "0.12.1"
+
[dependencies.syn]
version = "1.0"
features = ["full","extra-traits"]
diff --git a/src/generate/register.rs b/src/generate/register.rs
index f49f04d7..406173db 100644
--- a/src/generate/register.rs
+++ b/src/generate/register.rs
@@ -303,8 +303,8 @@ pub fn fields(
config: &Config,
) -> Result<()> {
let span = Span::call_site();
- let can_read = [Access::ReadOnly, Access::ReadWriteOnce, Access::ReadWrite].contains(&access);
- let can_write = access != Access::ReadOnly;
+ let can_read = access.can_read();
+ let can_write = access.can_write();
// TODO enumeratedValues
let inline = quote! { #[inline(always)] };
@@ -1263,7 +1263,7 @@ fn lookup_in_peripherals<'p>(
all_peripherals: &'p [Peripheral],
) -> Result<(&'p EnumeratedValues, Option>)> {
if let Some(peripheral) = all_peripherals.iter().find(|p| p.name == base_peripheral) {
- let all_registers = peripheral.reg_iter().collect::>();
+ let all_registers = peripheral.all_registers().collect::>();
lookup_in_peripheral(
Some(base_peripheral),
base_register,
diff --git a/src/lib.rs b/src/lib.rs
index d896a9bd..6ca95620 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -529,10 +529,10 @@ pub enum SvdError {
}
/// Generates rust code for the specified svd content.
-pub fn generate(xml: &str, config: &Config) -> Result {
+pub fn generate(input: &str, config: &Config) -> Result {
use std::fmt::Write;
- let device = svd_parser::parse(xml)?;
+ let device = crate::util::load_from(input, config)?;
let mut device_x = String::new();
let items =
generate::device::render(&device, config, &mut device_x).or(Err(SvdError::Render))?;
diff --git a/src/main.rs b/src/main.rs
index a7a43f19..f5f42a00 100755
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,7 +1,7 @@
#![recursion_limit = "128"]
use log::{error, info};
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
use svd_parser::svd;
mod generate;
@@ -14,7 +14,7 @@ use std::process;
use anyhow::{Context, Result};
use clap::{App, Arg};
-use crate::util::{build_rs, Config, Target};
+use crate::util::{build_rs, load_from, Config, Source, Target};
fn run() -> Result<()> {
use clap_conf::prelude::*;
@@ -84,6 +84,11 @@ fn run() -> Result<()> {
.short("s")
.help("Make advanced checks due to parsing SVD"),
)
+ .arg(
+ Arg::with_name("source_type")
+ .long("source_type")
+ .help("Specify file/stream format"),
+ )
.arg(
Arg::with_name("log_level")
.long("log")
@@ -101,19 +106,19 @@ fn run() -> Result<()> {
))
.get_matches();
- let xml = &mut String::new();
+ let input = &mut String::new();
match matches.value_of("input") {
Some(file) => {
File::open(file)
.context("Cannot open the SVD file")?
- .read_to_string(xml)
+ .read_to_string(input)
.context("Cannot read the SVD file")?;
}
None => {
let stdin = std::io::stdin();
stdin
.lock()
- .read_to_string(xml)
+ .read_to_string(input)
.context("Cannot read from stdin")?;
}
}
@@ -146,6 +151,18 @@ fn run() -> Result<()> {
cfg.bool_flag("ignore_groups", Filter::Arg) || cfg.bool_flag("ignore_groups", Filter::Conf);
let strict = cfg.bool_flag("strict", Filter::Arg) || cfg.bool_flag("strict", Filter::Conf);
+ let mut source_type = cfg
+ .grab()
+ .arg("source_type")
+ .conf("source_type")
+ .done()
+ .and_then(|s| Source::from_str(&s))
+ .unwrap_or_default();
+
+ if let Some(file) = matches.value_of("input") {
+ source_type = Source::from_path(Path::new(file))
+ }
+
let config = Config {
target,
nightly,
@@ -155,18 +172,11 @@ fn run() -> Result<()> {
ignore_groups,
strict,
output_dir: path.clone(),
- };
-
- let mut parser_config = svd_parser::Config::default();
- parser_config.validate_level = if strict {
- svd::ValidateLevel::Strict
- } else {
- svd::ValidateLevel::Weak
+ source_type,
};
info!("Parsing device from SVD file");
- let device = svd_parser::parse_with_config(xml, &parser_config)
- .with_context(|| "Error parsing SVD file".to_string())?;
+ let device = load_from(input, &config)?;
let mut device_x = String::new();
info!("Rendering device");
diff --git a/src/util.rs b/src/util.rs
index 6e01321a..bf3a4648 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -1,10 +1,10 @@
use std::borrow::Cow;
-use crate::svd::{Access, Cluster, Register, RegisterCluster, RegisterInfo};
+use crate::svd::{Access, Cluster, Device, Register, RegisterCluster, RegisterInfo, ValidateLevel};
use inflections::Inflect;
use proc_macro2::{Ident, Literal, Span, TokenStream};
use quote::{quote, ToTokens};
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
use anyhow::{anyhow, bail, Context, Result};
@@ -14,6 +14,26 @@ pub const BITS_PER_BYTE: u32 = 8;
/// that are not valid in Rust ident
const BLACKLIST_CHARS: &[char] = &['(', ')', '[', ']', '/', ' ', '-'];
+pub(crate) fn load_from(input: &str, config: &crate::util::Config) -> Result {
+ Ok(match config.source_type {
+ Source::Xml => {
+ let mut parser_config = svd_parser::Config::default();
+ parser_config.validate_level = if config.strict {
+ ValidateLevel::Strict
+ } else {
+ ValidateLevel::Weak
+ };
+
+ svd_parser::parse_with_config(input, &parser_config)
+ .with_context(|| "Error parsing SVD XML file".to_string())?
+ }
+ Source::Yaml => serde_yaml::from_str(input)
+ .with_context(|| "Error parsing SVD YAML file".to_string())?,
+ Source::Json => serde_json::from_str(input)
+ .with_context(|| "Error parsing SVD JSON file".to_string())?,
+ })
+}
+
#[derive(Clone, PartialEq, Debug)]
pub struct Config {
pub target: Target,
@@ -24,6 +44,7 @@ pub struct Config {
pub ignore_groups: bool,
pub strict: bool,
pub output_dir: PathBuf,
+ pub source_type: Source,
}
impl Default for Config {
@@ -37,6 +58,7 @@ impl Default for Config {
ignore_groups: false,
strict: false,
output_dir: PathBuf::from("."),
+ source_type: Source::default(),
}
}
}
@@ -73,6 +95,36 @@ impl Default for Target {
}
}
+#[derive(Clone, Copy, PartialEq, Debug)]
+pub enum Source {
+ Xml,
+ Yaml,
+ Json,
+}
+
+impl Default for Source {
+ fn default() -> Self {
+ Self::Xml
+ }
+}
+
+impl Source {
+ pub fn from_str(s: &str) -> Option {
+ match s {
+ "yml" | "yaml" => Some(Self::Yaml),
+ "json" => Some(Self::Json),
+ "xml" => Some(Self::Xml),
+ _ => None,
+ }
+ }
+ pub fn from_path(path: &Path) -> Self {
+ path.extension()
+ .and_then(|e| e.to_str())
+ .and_then(Self::from_str)
+ .unwrap_or_default()
+ }
+}
+
pub trait ToSanitizedPascalCase {
fn to_sanitized_pascal_case(&self) -> Cow;
}