use crate::ldf::ldf_comment::skip_whitespace;
use nom::{
bytes::complete::{tag, take_while},
AsChar, IResult,
};
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct LdfFrame {
pub frame_name: String,
pub frame_id: u8,
pub published_by: String,
pub frame_size: u8,
pub signals: Vec<LdfFrameSignal>,
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct LdfFrameSignal {
pub signal_name: String,
pub start_bit: u8,
}
pub fn parse_ldf_frames(s: &str) -> IResult<&str, Vec<LdfFrame>> {
let (s, _) = skip_whitespace(s)?;
let (s, _) = tag("Frames")(s)?;
let (s, _) = skip_whitespace(s)?;
let (s, _) = tag("{")(s)?;
let (s, _) = skip_whitespace(s)?;
let mut frames = Vec::new();
let mut remaining = s;
while !remaining.starts_with("}") {
let (s, frame) = parse_ldf_frame(remaining)?;
let (s, _) = skip_whitespace(s)?;
remaining = s;
frames.push(frame);
}
let (remaining, _) = tag("}")(remaining)?;
Ok((remaining, frames))
}
fn parse_ldf_frame(s: &str) -> IResult<&str, LdfFrame> {
let (s, _) = skip_whitespace(s)?;
let (s, frame_name) = take_while(|c: char| c.is_alphanumeric() || c == '_')(s)?;
let (s, _) = skip_whitespace(s)?;
let (s, _) = tag(":")(s)?;
let (s, _) = skip_whitespace(s)?;
let (s, frame_id) = take_while(|c: char| c.is_hex_digit() || c == 'x')(s)?;
let (s, _) = skip_whitespace(s)?;
let (s, _) = tag(",")(s)?;
let (s, _) = skip_whitespace(s)?;
let (s, published_by) = take_while(|c: char| c.is_alphanumeric() || c == '_')(s)?;
let (s, _) = skip_whitespace(s)?;
let (s, _) = tag(",")(s)?;
let (s, _) = skip_whitespace(s)?;
let (s, frame_size) = take_while(|c: char| c.is_numeric())(s)?;
let (s, _) = skip_whitespace(s)?;
let (s, _) = tag("{")(s)?;
let (s, _) = skip_whitespace(s)?;
let mut signals = Vec::new();
let mut remaining = s;
while !remaining.starts_with("}") {
let (s, signal) = parse_ldf_frame_signal(remaining)?;
let (s, _) = skip_whitespace(s)?;
remaining = s;
signals.push(signal);
}
let (remaining, _) = tag("}")(remaining)?;
Ok((
remaining,
LdfFrame {
frame_name: frame_name.to_string(),
frame_id: {
if frame_id.starts_with("0x") {
u8::from_str_radix(&frame_id[2..], 16).unwrap()
} else {
frame_id.parse().unwrap()
}
},
published_by: published_by.to_string(),
frame_size: frame_size.parse().unwrap(),
signals,
},
))
}
fn parse_ldf_frame_signal(s: &str) -> IResult<&str, LdfFrameSignal> {
let (s, _) = skip_whitespace(s)?;
let (s, signal_name) = take_while(|c: char| c.is_alphanumeric() || c == '_')(s)?;
let (s, _) = skip_whitespace(s)?;
let (s, _) = tag(",")(s)?;
let (s, _) = skip_whitespace(s)?;
let (s, start_bit) = take_while(|c: char| c.is_numeric())(s)?;
let (s, _) = skip_whitespace(s)?;
let (s, _) = tag(";")(s)?;
Ok((
s,
LdfFrameSignal {
signal_name: signal_name.to_string(),
start_bit: start_bit.parse().unwrap(),
},
))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_ldf_frames() {
let input = r#"
Frames {
Frame1: 0, Master, 8 {
Signal1, 0 ;
Signal2, 10 ;
}
Frame2: 0x16, Slave1, 8 {
Signal3, 0 ;
Signal4, 10 ;
}
}
"#;
let (_, frames) = parse_ldf_frames(input).unwrap();
assert_eq!(frames.len(), 2);
assert_eq!(frames[0].frame_name, "Frame1");
assert_eq!(frames[0].frame_id, 0);
assert_eq!(frames[0].published_by, "Master");
assert_eq!(frames[0].frame_size, 8);
assert_eq!(frames[0].signals.len(), 2);
assert_eq!(frames[0].signals[0].signal_name, "Signal1");
assert_eq!(frames[0].signals[0].start_bit, 0);
assert_eq!(frames[0].signals[1].signal_name, "Signal2");
assert_eq!(frames[0].signals[1].start_bit, 10);
assert_eq!(frames[1].frame_name, "Frame2");
assert_eq!(frames[1].frame_id, 0x16);
assert_eq!(frames[1].published_by, "Slave1");
assert_eq!(frames[1].frame_size, 8);
assert_eq!(frames[1].signals.len(), 2);
assert_eq!(frames[1].signals[0].signal_name, "Signal3");
assert_eq!(frames[1].signals[0].start_bit, 0);
assert_eq!(frames[1].signals[1].signal_name, "Signal4");
assert_eq!(frames[1].signals[1].start_bit, 10);
}
}