use std::fmt;
use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::character::complete::line_ending;
use nom::combinator::{map, opt};
use nom::multi::{many0, separated_list0};
use nom::sequence::{delimited, pair, separated_pair};
use nom::{IResult, Parser};
use super::char_string::{parser_char_string, CharString};
use super::common_parsers::{
multispacey, number_value, parser_node_name, parser_signal_name, spacey, unsigned_integer,
};
use super::error::DbcParseError;
#[derive(PartialEq, Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MultiplexerIndicator {
pub multiplexer_signal: Option<u32>,
pub multiplexer_switch: Option<()>,
}
impl fmt::Display for MultiplexerIndicator {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(multiplexer_signal) = self.multiplexer_signal {
write!(f, "m{multiplexer_signal}")?;
}
if let Some(()) = self.multiplexer_switch {
write!(f, "M")?;
}
Ok(())
}
}
#[derive(PartialEq, Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ByteOrder {
LittleEndian,
BigEndian,
}
impl fmt::Display for ByteOrder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ByteOrder::LittleEndian => write!(f, "1"),
ByteOrder::BigEndian => write!(f, "0"),
}
}
}
#[derive(PartialEq, Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ValueType {
Signed,
Unsigned,
}
impl fmt::Display for ValueType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ValueType::Signed => write!(f, "-"),
ValueType::Unsigned => write!(f, "+"),
}
}
}
#[derive(PartialEq, Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Signal {
pub name: String,
pub multiplexer: Option<MultiplexerIndicator>,
pub start_bit: u32,
pub size: u32,
pub byte_order: ByteOrder,
pub value_type: ValueType,
pub factor: f64,
pub offset: f64,
pub min: Option<f64>,
pub max: Option<f64>,
pub unit: Option<CharString>,
pub receivers: Option<Vec<String>>,
}
impl fmt::Display for Signal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let multiplexer = match &self.multiplexer {
Some(m) => format!("{m} "),
None => String::new(),
};
let value_type = match &self.value_type {
ValueType::Signed => "-",
ValueType::Unsigned => "+",
};
let byte_order = &self.byte_order.to_string();
let min_max = match (&self.min, &self.max) {
(Some(min), Some(max)) => format!("[{min}|{max}]"),
_ => String::new(),
};
let unit = match &self.unit {
Some(u) => format!(r#""{u}""#),
None => String::new(),
};
let mut receivers_str = String::new();
if let Some(nodes) = &self.receivers {
receivers_str = nodes.join(",");
}
write!(
f,
"SG_ {} {}: {}|{}@{}{} ({},{}) {} {} {}",
self.name,
multiplexer,
self.start_bit,
self.size,
byte_order,
value_type,
self.factor,
self.offset,
min_max,
unit,
receivers_str
)
}
}
fn parser_signal_multiplexer(input: &str) -> IResult<&str, MultiplexerIndicator, DbcParseError> {
map(
(opt(pair(tag("m"), unsigned_integer)), opt(tag("M"))),
|(multiplexer_signal, multiplexer_switch)| MultiplexerIndicator {
multiplexer_signal: multiplexer_signal.map(|(_, num)| num),
multiplexer_switch: multiplexer_switch.map(|_| ()),
},
)
.parse(input)
}
fn parser_signal_multiplexer_option(
input: &str,
) -> IResult<&str, Option<MultiplexerIndicator>, DbcParseError> {
let res = parser_signal_multiplexer(input)?;
if res.1.multiplexer_signal.is_none() && res.1.multiplexer_switch.is_none() {
return Ok((res.0, None));
}
Ok((res.0, Some(res.1)))
}
fn parser_signal_start_bit(input: &str) -> IResult<&str, u32, DbcParseError> {
unsigned_integer(input)
}
fn parser_signal_size(input: &str) -> IResult<&str, u32, DbcParseError> {
unsigned_integer(input)
}
fn parser_signal_byte_order(input: &str) -> IResult<&str, ByteOrder, DbcParseError> {
alt((
map(tag("1"), |_| ByteOrder::LittleEndian),
map(tag("0"), |_| ByteOrder::BigEndian),
))
.parse(input)
}
fn parser_signal_value_type(input: &str) -> IResult<&str, ValueType, DbcParseError> {
alt((
map(tag("+"), |_| ValueType::Unsigned),
map(tag("-"), |_| ValueType::Signed),
))
.parse(input)
}
fn parser_signal_factor_offset(input: &str) -> IResult<&str, (f64, f64), DbcParseError> {
let (remain, (factor, offset)) = delimited(
spacey(tag("(")),
separated_pair(number_value, spacey(tag(",")), number_value),
spacey(tag(")")),
)
.parse(input)?;
Ok((remain, (factor, offset)))
}
fn parser_signal_min_max(input: &str) -> IResult<&str, (f64, f64), DbcParseError> {
let (remain, (min_value, max_value)) = delimited(
spacey(tag("[")),
separated_pair(number_value, spacey(tag("|")), number_value),
spacey(tag("]")),
)
.parse(input)?;
Ok((remain, (min_value, max_value)))
}
fn parser_signal_unit(input: &str) -> IResult<&str, CharString, DbcParseError> {
parser_char_string(input)
}
fn parser_signal_receivers(input: &str) -> IResult<&str, Vec<String>, DbcParseError> {
let (remain, nodes) =
spacey(separated_list0(tag(","), spacey(parser_node_name))).parse(input)?;
Ok((remain, nodes.into_iter().map(String::from).collect()))
}
pub fn parser_signal(input: &str) -> IResult<&str, Signal, DbcParseError> {
let res = map(
(
multispacey(tag("SG_")),
spacey(parser_signal_name),
spacey(parser_signal_multiplexer_option),
spacey(tag(":")),
spacey(parser_signal_start_bit),
spacey(tag("|")),
spacey(parser_signal_size),
spacey(tag("@")),
spacey(parser_signal_byte_order),
spacey(parser_signal_value_type),
spacey(parser_signal_factor_offset),
spacey(opt(parser_signal_min_max)),
spacey(opt(parser_signal_unit)),
spacey(opt(parser_signal_receivers)),
many0(line_ending),
),
|(
_,
name,
multiplexer,
_,
start_bit,
_,
size,
_,
byte_order,
value_type,
factor_offset,
min_max,
unit,
receiving_nodes,
_,
)| Signal {
name: String::from(name),
multiplexer,
start_bit,
size,
byte_order,
value_type,
factor: factor_offset.0,
offset: factor_offset.1,
min: min_max.map(|(min, _)| min),
max: min_max.map(|(_, max)| max),
unit,
receivers: receiving_nodes,
},
)
.parse(input);
match res {
Ok((remain, signal)) => {
log::info!("parse signal: {signal:?}");
Ok((remain, signal))
}
Err(e) => {
log::trace!("parse signal failed, e = {e:?}");
Err(nom::Err::Error(DbcParseError::BadSignal))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_dbc_signal_multiplexer_01() {
assert_eq!(
parser_signal_multiplexer("M"),
Ok((
"",
MultiplexerIndicator {
multiplexer_signal: None,
multiplexer_switch: Some(())
}
)),
);
}
#[test]
fn test_dbc_signal_multiplexer_02() {
assert_eq!(
parser_signal_multiplexer("m0"),
Ok((
"",
MultiplexerIndicator {
multiplexer_signal: Some(0),
multiplexer_switch: None
}
)),
);
}
#[test]
fn test_dbc_signal_multiplexer_03() {
assert_eq!(
parser_signal_multiplexer("m123"),
Ok((
"",
MultiplexerIndicator {
multiplexer_signal: Some(123),
multiplexer_switch: None
}
)),
);
}
#[test]
fn test_dbc_signal_multiplexer_04() {
assert_eq!(
parser_signal_multiplexer("m3M"),
Ok((
"",
MultiplexerIndicator {
multiplexer_signal: Some(3),
multiplexer_switch: Some(())
}
)),
);
}
#[test]
fn test_dbc_signal_01() {
let ret = parser_signal(
r#" SG_ AY1 : 32|16@1+ (0.000127465,-4.1768) [-4.1768|4.1765] "g" ABS
"#,
);
match ret {
Ok((_remain, signal)) => {
assert_eq!(
signal,
Signal {
name: "AY1".into(),
multiplexer: None,
start_bit: 32,
size: 16,
byte_order: ByteOrder::LittleEndian,
value_type: ValueType::Unsigned,
factor: 0.000_127_465,
offset: -4.1768,
min: Some(-4.1768),
max: Some(4.1765),
unit: Some(CharString("g".into())),
receivers: Some(vec!["ABS".into()]),
}
);
}
Err(err) => panic!("err = {err:?}"),
}
}
#[test]
fn test_dbc_signal_02() {
let ret = parser_signal(
r#" SG_ S2 m0 : 8|8@1- (1.0,0.0) [0.0|0.0] "" Vector__XXX
"#,
);
match ret {
Ok((_remain, signal)) => {
assert_eq!(
signal,
Signal {
name: "S2".into(),
multiplexer: Some(MultiplexerIndicator {
multiplexer_signal: Some(0),
multiplexer_switch: None
}),
start_bit: 8,
size: 8,
byte_order: ByteOrder::LittleEndian,
value_type: ValueType::Signed,
factor: 1.0,
offset: 0.0,
min: Some(0.0),
max: Some(0.0),
unit: Some(CharString(String::new())),
receivers: Some(vec!["Vector__XXX".into()]),
}
);
}
Err(err) => panic!("err = {err:?}"),
}
}
#[test]
fn test_dbc_signal_03() {
let ret = parser_signal(
r#" SG_ S2 m0 : 8|8@1- (1,0) [0|0] "" Vector__XXX
"#,
);
match ret {
Ok((_remain, signal)) => {
assert_eq!(
signal,
Signal {
name: "S2".into(),
multiplexer: Some(MultiplexerIndicator {
multiplexer_signal: Some(0),
multiplexer_switch: None
}),
start_bit: 8,
size: 8,
byte_order: ByteOrder::LittleEndian,
value_type: ValueType::Signed,
factor: 1.0,
offset: 0.0,
min: Some(0.0),
max: Some(0.0),
unit: Some(CharString(String::new())),
receivers: Some(vec!["Vector__XXX".into()]),
}
);
}
Err(err) => panic!("err = {err:?}"),
}
}
#[test]
fn test_dbc_signal_04() {
let ret = parser_signal(
r#" SG_ Signal1 : 32|32@1+ (100,0) [0|100] "%" Node1,Node2
"#,
);
match ret {
Ok((_remain, signal)) => {
assert_eq!(
signal,
Signal {
name: "Signal1".into(),
multiplexer: None,
start_bit: 32,
size: 32,
byte_order: ByteOrder::LittleEndian,
value_type: ValueType::Unsigned,
factor: 100.0,
offset: 0.0,
min: Some(0.0),
max: Some(100.0),
unit: Some(CharString("%".into())),
receivers: Some(vec!["Node1".into(), "Node2".into()]),
}
);
}
Err(err) => panic!("err = {err:?}"),
}
}
}