diff --git a/src/reg/registry.rs b/src/reg/registry.rs index c808e85..be637d1 100644 --- a/src/reg/registry.rs +++ b/src/reg/registry.rs @@ -735,6 +735,33 @@ impl Registry { self.characteristic_list.iter().find(|c| c.name == name) } + #[cfg(feature = "check_a2l")] + pub fn a2l_load(&mut self, filename: &str) -> Result { + trace!("Load A2L file {}", filename); + let input_filename = &std::ffi::OsString::from(filename); + let mut logmsgs = Vec::::new(); + let res = a2lfile::load(input_filename, None, &mut logmsgs, true); + for log_msg in logmsgs { + warn!("A2l Loader: {}", log_msg); + } + match res { + Ok(a2l_file) => { + // Perform a consistency check + let mut logmsgs = Vec::::new(); + a2l_file.check(&mut logmsgs); + for log_msg in logmsgs { + warn!("A2l Checker: {}", log_msg); + } + Ok(a2l_file) + } + + Err(e) => { + error!("a2lfile::load failed: {:?}", e); + Err(e) + } + } + } + /// Generate A2L file from registry pub fn write_a2l(&mut self) -> Result<(), std::io::Error> { // Error if registry is closed @@ -743,13 +770,30 @@ impl Registry { } // Sort measurement and calibration lists to get deterministic order - // Event and CalSeg lists stay in the order they were added + // Event and CalSeg lists stay in the order the were added self.measurement_list.sort(); self.characteristic_list.sort(); // Write to A2L file - let writer = A2lWriter::new(); - writer.write_a2l(self) + let a2l_name = self.name.unwrap(); + let a2l_path = format!("{}.a2l", a2l_name); + let a2l_file = std::fs::File::create(&a2l_path)?; + let a2l_file_writer: &mut dyn std::io::Write = &mut std::io::LineWriter::new(a2l_file); + let mut writer = A2lWriter::new(a2l_file_writer); + writer.write_a2l(a2l_name, a2l_name, self)?; + + // @@@@ Dev + // Check A2L file + #[cfg(feature = "check_a2l")] + { + if let Err(e) = self.a2l_load(&a2l_path) { + error!("a2lfile::load failed: {:?}", e); + } else { + info!("A2L file check ok"); + } + } + + Ok(()) } } diff --git a/src/reg/registry/a2l_writer.rs b/src/reg/registry/a2l_writer.rs index 641daed..66b8031 100644 --- a/src/reg/registry/a2l_writer.rs +++ b/src/reg/registry/a2l_writer.rs @@ -2,10 +2,7 @@ // Sub Module a2l_writer // Export an A2L file from super::registry -use std::{ - fs::File, - io::{LineWriter, Write}, -}; +use std::io::Write; #[allow(unused_imports)] use log::{debug, error, info, trace, warn}; @@ -268,19 +265,18 @@ impl GenerateA2l for RegistryCharacteristic { //------------------------------------------------------------------------------------------------- -#[derive(Debug)] -pub struct A2lWriter {} +pub struct A2lWriter<'a> { + writer: &'a mut dyn Write, +} -impl A2lWriter { - pub fn new() -> A2lWriter { - A2lWriter {} +impl<'a> A2lWriter<'a> { + pub fn new(writer: &'a mut dyn Write) -> A2lWriter { + A2lWriter { writer } } - fn write_a2l_head(&self, writer: &mut dyn Write, a2l_name: &str) -> std::io::Result<()> { - let project_name = a2l_name; - let module_name = a2l_name; + fn write_a2l_head(&mut self, project_name: &str, module_name: &str) -> std::io::Result<()> { write!( - writer, + self.writer, r#" ASAP2_VERSION 1 71 /begin PROJECT {project_name} "" @@ -343,24 +339,24 @@ impl A2lWriter { ) } - fn write_a2l_modpar(&self, writer: &mut dyn Write, registry: &Registry) -> std::io::Result<()> { + fn write_a2l_modpar(&mut self, registry: &Registry) -> std::io::Result<()> { // EPK segment let mod_par = ®istry.mod_par; // // Memory segments from calibration segments let memory_segments = ®istry.cal_seg_list; - write!(writer, "\n\t\t/begin MOD_PAR \"\"")?; + write!(self.writer, "\n\t\t/begin MOD_PAR \"\"")?; - mod_par.write_a2l(writer)?; - memory_segments.write_a2l(writer)?; + mod_par.write_a2l(self.writer)?; + memory_segments.write_a2l(self.writer)?; - writeln!(writer, "\n\t\t/end MOD_PAR") + writeln!(self.writer, "\n\t\t/end MOD_PAR") } - fn write_a2l_if_data(&self, writer: &mut dyn Write, registry: &Registry) -> std::io::Result<()> { + fn write_a2l_if_data(&mut self, registry: &Registry) -> std::io::Result<()> { write!( - writer, + self.writer, r#" /begin IF_DATA XCP /begin PROTOCOL_LAYER @@ -398,7 +394,7 @@ impl A2lWriter { let event_count = registry.event_list.len(); write!( - writer, + self.writer, "\n\n\t\t\t/begin DAQ DYNAMIC 0 {event_count} 0 OPTIMISATION_TYPE_DEFAULT ADDRESS_EXTENSION_FREE IDENTIFICATION_FIELD_TYPE_RELATIVE_BYTE GRANULARITY_ODT_ENTRY_SIZE_DAQ_BYTE 0xF8 OVERLOAD_INDICATION_PID /begin TIMESTAMP_SUPPORTED @@ -409,24 +405,24 @@ impl A2lWriter { // Eventlist for e in registry.event_list.iter() { - e.write_a2l(writer)? + e.write_a2l(self.writer)? } - write!(writer, "\n\t\t\t/end DAQ\n")?; + write!(self.writer, "\n\t\t\t/end DAQ\n")?; // Transport layer parameters in IF_DATA if let Some(tl_params) = registry.tl_params { - tl_params.write_a2l(writer)?; + tl_params.write_a2l(self.writer)?; } - write!(writer, "\n\t\t/end IF_DATA\n")?; + write!(self.writer, "\n\t\t/end IF_DATA\n")?; Ok(()) } - fn write_a2l_measurements(&self, writer: &mut dyn Write, registry: &Registry) -> std::io::Result<()> { + fn write_a2l_measurements(&mut self, registry: &Registry) -> std::io::Result<()> { // Measurements for m in registry.measurement_list.iter() { - m.write_a2l(writer)?; + m.write_a2l(self.writer)?; } // Create a root measurement group for each event, if more than one element @@ -436,24 +432,24 @@ impl A2lWriter { continue; } if registry.measurement_list.iter().filter(|m| m.event.get_name() == e.get_name()).count() > 1 { - write!(writer, "\n/begin GROUP {} \"\" ROOT /begin REF_MEASUREMENT", e.get_name())?; + write!(self.writer, "\n/begin GROUP {} \"\" ROOT /begin REF_MEASUREMENT", e.get_name())?; for m in registry.measurement_list.iter() { if m.event.get_name() == e.get_name() { - write!(writer, " {}", m.name)?; + write!(self.writer, " {}", m.name)?; } } - write!(writer, " /end REF_MEASUREMENT /end GROUP")?; + write!(self.writer, " /end REF_MEASUREMENT /end GROUP")?; } } Ok(()) } - fn write_a2l_characteristics(&self, writer: &mut dyn Write, registry: &Registry) -> std::io::Result<()> { + fn write_a2l_characteristics(&mut self, registry: &Registry) -> std::io::Result<()> { // Characteristics not in a in calibration segment for c in registry.characteristic_list.iter() { if c.calseg_name.is_none() { - c.write_a2l(writer)?; + c.write_a2l(self.writer)?; } } @@ -463,54 +459,27 @@ impl A2lWriter { for c in registry.characteristic_list.iter() { if let Some(calseg_name) = c.calseg_name { if s.name == calseg_name { - c.write_a2l(writer)?; + c.write_a2l(self.writer)?; } } } // Characteristic group for each calibration segment - write!(writer, "\n/begin GROUP {} \"\" ROOT /begin REF_CHARACTERISTIC ", s.name)?; + write!(self.writer, "\n/begin GROUP {} \"\" ROOT /begin REF_CHARACTERISTIC ", s.name)?; for c in registry.characteristic_list.iter() { if let Some(calseg_name) = c.calseg_name { if s.name == calseg_name { - write!(writer, " {} ", c.name.as_str())?; + write!(self.writer, " {} ", c.name.as_str())?; } } } - writeln!(writer, "/end REF_CHARACTERISTIC /end GROUP\n")?; + writeln!(self.writer, "/end REF_CHARACTERISTIC /end GROUP\n")?; } Ok(()) } - #[cfg(feature = "check_a2l")] - pub fn a2l_load(&self, filename: &str) -> Result { - trace!("Load A2L file {}", filename); - let input_filename = &std::ffi::OsString::from(filename); - let mut logmsgs = Vec::::new(); - let res = a2lfile::load(input_filename, None, &mut logmsgs, true); - for log_msg in logmsgs { - warn!("A2l Loader: {}", log_msg); - } - match res { - Ok(a2l_file) => { - // Perform a consistency check - let mut logmsgs = Vec::::new(); - a2l_file.check(&mut logmsgs); - for log_msg in logmsgs { - warn!("A2l Checker: {}", log_msg); - } - Ok(a2l_file) - } - - Err(e) => { - error!("a2lfile::load failed: {:?}", e); - Err(e) - } - } - } - - fn write_a2l_tail(&self, writer: &mut dyn Write) -> std::io::Result<()> { - writer.write_all( + fn write_a2l_tail(&mut self) -> std::io::Result<()> { + self.writer.write_all( r#" /end MODULE /end PROJECT @@ -519,36 +488,16 @@ impl A2lWriter { ) } - pub fn write_a2l(&self, registry: &Registry) -> Result<(), std::io::Error> { - if let Some(a2l_name) = ®istry.name { - // Write to file - let a2l_path = format!("{}.a2l", a2l_name); - let a2l_file = File::create(&a2l_path)?; - let a2l_file_writer: &mut dyn Write = &mut LineWriter::new(a2l_file); - - self.write_a2l_head(a2l_file_writer, a2l_name)?; - self.write_a2l_modpar(a2l_file_writer, registry)?; - self.write_a2l_if_data(a2l_file_writer, registry)?; - self.write_a2l_measurements(a2l_file_writer, registry)?; - self.write_a2l_characteristics(a2l_file_writer, registry)?; - self.write_a2l_tail(a2l_file_writer)?; - - info!("Write A2L file {}", a2l_path); - - // @@@@ Dev - // Check A2L file - #[cfg(feature = "check_a2l")] - { - if let Err(e) = self.a2l_load(&a2l_path) { - error!("a2lfile::load failed: {:?}", e); - } else { - info!("A2L file check ok"); - } - } + pub fn write_a2l(&mut self, project_name: &str, module_name: &str, registry: &Registry) -> Result<(), std::io::Error> { + self.write_a2l_head(project_name, module_name)?; + self.write_a2l_modpar(registry)?; + self.write_a2l_if_data(registry)?; + self.write_a2l_measurements(registry)?; + self.write_a2l_characteristics(registry)?; + self.write_a2l_tail()?; - Ok(()) - } else { - Err(std::io::Error::new(std::io::ErrorKind::Other, "No name set")) - } + info!("Write A2L file {},{}", project_name, module_name); + + Ok(()) } }