rrdbc/ast/
bit_timing.rs

1use std::fmt;
2
3use nom::bytes::complete::tag;
4use nom::character::complete::{line_ending, u64};
5use nom::combinator::{map, opt};
6use nom::multi::many0;
7use nom::{IResult, Parser};
8
9use super::common_parsers::{multispacey, spacey};
10use super::error::DbcParseError;
11
12#[derive(PartialEq, Debug, Clone)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14pub struct BitTimingValue {
15    // Baud rate
16    pub baudrate: u64,
17    // bit timing register 1
18    pub btr1: u64,
19    // bit timing register 2
20    pub btr2: u64,
21}
22
23impl fmt::Display for BitTimingValue {
24    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25        write!(f, "{}:{}:{}", self.baudrate, self.btr1, self.btr2)
26    }
27}
28
29/// The bit timing section defines the baudrate and the settings of the BTR registers of
30/// the network. This section is obsolete and not used anymore. Nevertheless, the
31/// keyword `BS_` must appear in the DBC file.
32///
33/// Format: `bit_timing = BS_: [baudrate : BTR1 , BTR2 ] ;`
34#[derive(PartialEq, Debug, Clone)]
35#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
36pub struct BitTiming {
37    pub value: Option<BitTimingValue>,
38}
39
40impl fmt::Display for BitTiming {
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        match &self.value {
43            Some(value) => writeln!(f, "BS_: {value}"),
44            None => writeln!(f, "BS_:"),
45        }
46    }
47}
48
49pub fn parser_bit_timing_value(input: &str) -> IResult<&str, BitTimingValue, DbcParseError> {
50    let res: Result<(&str, BitTimingValue), nom::Err<DbcParseError>> = map(
51        (
52            spacey(u64),
53            spacey(tag(":")),
54            spacey(u64),
55            spacey(tag(":")),
56            spacey(u64),
57        ),
58        |(baudrate, _, btr1, _, btr2)| BitTimingValue {
59            baudrate,
60            btr1,
61            btr2,
62        },
63    )
64    .parse(input);
65    match res {
66        Ok((remain, bit_timing)) => {
67            log::info!("parse bit timing value: {bit_timing:?}");
68            Ok((remain, bit_timing))
69        }
70        Err(e) => {
71            log::trace!("parse bit timing value failed, e = {e:?}");
72            Err(nom::Err::Error(DbcParseError::BadBitTimingValue))
73        }
74    }
75}
76
77pub fn parser_bit_timing(input: &str) -> IResult<&str, Option<BitTiming>, DbcParseError> {
78    let res = map(
79        (
80            multispacey(tag("BS_")),
81            spacey(tag(":")),
82            spacey(opt(parser_bit_timing_value)),
83            spacey(opt(tag(";"))),
84            many0(line_ending),
85        ),
86        |(_, _, value, _, _)| match value {
87            None => Some(BitTiming { value: None }),
88            Some(value) => Some(BitTiming { value: Some(value) }),
89        },
90    )
91    .parse(input);
92    match res {
93        Ok((remain, bit_timing)) => {
94            log::info!("parse bit timing: {bit_timing:?}");
95            Ok((remain, bit_timing))
96        }
97        Err(e) => {
98            log::trace!("parse bit timing failed, e = {e:?}");
99            Err(nom::Err::Error(DbcParseError::BadBitTiming))
100        }
101    }
102}
103
104#[cfg(test)]
105mod tests {
106    use super::*;
107
108    #[test]
109    fn test_parser_bit_timing_01() {
110        let ret = parser_bit_timing(
111            "BS_: 12:123:456
112
113",
114        );
115        match ret {
116            Ok((_remain, bus_config)) => {
117                assert_eq!(
118                    bus_config,
119                    Some(BitTiming {
120                        value: Some(BitTimingValue {
121                            baudrate: 12,
122                            btr1: 123,
123                            btr2: 456,
124                        })
125                    })
126                );
127            }
128            Err(err) => panic!("err = {err:?}"),
129        }
130    }
131
132    #[test]
133    fn test_parser_bit_timing_02() {
134        let ret = parser_bit_timing(
135            "BS_:
136
137",
138        );
139        match ret {
140            Ok((_remain, bus_config)) => {
141                assert_eq!(bus_config, Some(BitTiming { value: None }));
142            }
143            Err(err) => panic!("err = {err:?}"),
144        }
145    }
146
147    #[test]
148    fn test_parser_bit_timing_03() {
149        let ret = parser_bit_timing(
150            "BS_: ;
151
152",
153        );
154        match ret {
155            Ok((_remain, bus_config)) => {
156                assert_eq!(bus_config, Some(BitTiming { value: None }));
157            }
158            Err(err) => panic!("err = {err:?}"),
159        }
160    }
161
162    #[test]
163    fn test_parser_bit_timing_04() {
164        let ret = parser_bit_timing(
165            "BS_: 12:123:456 ;
166
167",
168        );
169        match ret {
170            Ok((_remain, bus_config)) => {
171                assert_eq!(
172                    bus_config,
173                    Some(BitTiming {
174                        value: Some(BitTimingValue {
175                            baudrate: 12,
176                            btr1: 123,
177                            btr2: 456,
178                        })
179                    })
180                );
181            }
182            Err(err) => panic!("err = {err:?}"),
183        }
184    }
185
186    #[test]
187    fn test_bit_timing_string_01() {
188        let bit_timing = BitTiming {
189            value: Some(BitTimingValue {
190                baudrate: 12,
191                btr1: 123,
192                btr2: 456,
193            }),
194        };
195        assert_eq!(bit_timing.to_string(), "BS_: 12:123:456\n");
196    }
197
198    #[test]
199    fn test_bit_timing_string_02() {
200        let bit_timing = BitTiming { value: None };
201        assert_eq!(bit_timing.to_string(), "BS_:\n");
202    }
203}