endcap-sl-software-ri-gener.../src/integrated.rs

142 lines
4.3 KiB
Rust

use std::path;
use itertools::Itertools;
use thiserror::Error;
use crate::{
converter, generator,
io::{get_xml_gitinfo, XmlGitInfoError},
types, validator,
};
#[derive(Debug, Error)]
pub enum Error {
#[error("error in getting xml git info: {0}")]
XmlGitInfoError(#[from] XmlGitInfoError),
#[error("io error: {0}")]
IOError(#[from] std::io::Error),
#[error("xml parse error: {0}")]
XmlParseError(#[from] roxmltree::Error),
#[error("dom conversion error: {0}")]
DomConversionError(#[from] converter::DomConversionError),
#[error("invalid register map:\n{}", ._0.iter().map(|e| e.to_string()).join("\n"))]
RegmapValidationError(Vec<validator::ValidationError>),
#[error("code generation error: {0}")]
CodeGenError(#[from] generator::CodeGenError),
#[cfg(feature = "flatmap")]
#[error("csv write error: {0}")]
CsvWriteError(#[from] csv::Error),
}
/// Generate register interface code from xml in `xml` and write them under directory `out`.
pub fn generate(xml: &path::Path, out: &path::Path) -> Result<(), Error> {
log::debug!("generate called: xml:{:?}, out: {:?}", xml, out);
let xml_git_info = get_xml_gitinfo(xml)?;
log::debug!("xml git info {xml_git_info:?}");
let xmlfile = std::fs::read_to_string(xml)?;
let doc = roxmltree::Document::parse_with_options(
&xmlfile,
roxmltree::ParsingOptions {
allow_dtd: true,
nodes_limit: u32::MAX,
},
)?;
log::debug!("xml parsed {doc:?}");
let register_map = types::Module::from_xml_dom(doc.root_element(), xml_git_info)?;
log::debug!("converted {register_map:?}");
let (_maps, errors) = register_map.validate();
if !errors.is_empty() {
return Err(Error::RegmapValidationError(errors));
}
let files = register_map.generate_code()?;
if log::log_enabled!(log::Level::Debug) {
for (path, code) in &files {
log::debug!("path: {:?}", path);
log::debug!("{}", prettyplease::unparse(code));
log::trace!("{}", prettyplease::unparse(code));
}
}
crate::write_to_files(files, out)?;
log::debug!("wrote to files");
Ok(())
}
#[cfg(feature = "flatmap")]
pub fn generate_flatmap(xml: &path::Path, out: Option<&path::Path>) -> Result<(), Error> {
use std::{
fs::File,
io::{self, BufWriter, Write},
};
log::debug!("generate called: xml:{:?}, out: {:?}", xml, out);
let xml_git_info = get_xml_gitinfo(xml)?;
log::debug!("xml git info {xml_git_info:?}");
let xmlfile = std::fs::read_to_string(xml)?;
let doc = roxmltree::Document::parse_with_options(
&xmlfile,
roxmltree::ParsingOptions {
allow_dtd: true,
nodes_limit: u32::MAX,
},
)?;
log::debug!("xml parsed {doc:?}");
let register_map = types::Module::from_xml_dom(doc.root_element(), xml_git_info)?;
log::debug!("converted {register_map:?}");
let (maps, errors) = register_map.validate();
if !errors.is_empty() {
return Err(Error::RegmapValidationError(errors));
}
let f: Box<dyn Write> = match out {
Some(f) => {
let file = File::options().write(true).truncate(true).open(f)?;
Box::new(BufWriter::new(file))
}
None => Box::new(io::stdout()),
};
let mut wtr = csv::Writer::from_writer(f);
wtr.write_record([
"address",
"path",
"name",
"multiple_id",
"modf",
"description",
])?;
for (addr, reg) in maps.iter().enumerate() {
match reg {
Some(reg) => {
let path = reg.0.join("/");
let multiple_id = reg.2.map_or("".to_string(), |x| x.to_string());
wtr.write_record([
format!("0x{:04x}", addr),
path,
reg.1.name.clone(),
multiple_id,
reg.1.modf.to_string(),
reg.1.desc.as_ref().unwrap_or(&"".to_string()).to_string(),
])?;
}
None => wtr.write_record([
format!("0x{:04x}", addr),
"".to_string(),
"".to_string(),
"".to_string(),
"".to_string(),
"".to_string(),
])?,
}
}
Ok(())
}