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 pub baudrate: u64,
17 pub btr1: u64,
19 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#[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}