lin_ldf/ldf/ldf_signals.rs
1use crate::ldf::ldf_comment::skip_whitespace;
2use nom::{
3 bytes::complete::{tag, take_until, take_while},
4 IResult,
5};
6
7/// The init_value specifies the signal value that shall be used by all subscriber nodes.
8/// The init_value_scalar is used for scalar signals and the init_value_array is used for byte array signals.
9#[derive(Debug, PartialEq)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11pub enum LdfSignalInitValue {
12 Scalar(u8),
13 Array(Vec<u8>),
14}
15
16/// `Signals` section of a LIN Description File (LDF) for LIN 2.1
17/// ```text
18/// Signals {
19/// Signal1: 10, 0, Master, Slave1 ;
20/// Signal2: 10, 0, Master, Slave1 ;
21/// Signal3: 10, 0, Master, Slave1 ;
22/// Signal4: 10, 0, Slave1, Master ;
23/// Signal5: 2, 0, Slave1, Master ;
24/// Signal6: 1, 0, Slave1, Master ;
25/// }
26/// ```
27/// ---
28/// Signal in the `Signals` section of a LIN Description File (LDF) for LIN 2.1
29/// ```text
30/// Signal1: 10, 0, Master, Slave1 ;
31/// ```
32/// Reads as:
33/// ```text
34/// <signal_name>: <signal_size>, <init_value>, <published_by> [, <subscribed_by>] ;
35/// ```
36#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
37pub struct LdfSignal {
38 /// All identifiers must be unique within the LDF file.
39 pub name: String,
40
41 /// The signal_size specifies the size of the signal. It shall be in the range 1 to 16 bits for
42 /// scalar signals and 8, 16, 24, 32, 40, 48, 56 or 64 for byte array signals.
43 pub signal_size: u8,
44
45 /// ```text
46 /// <init_value> ::= <init_value_scalar> | <init_value_array>
47 /// <init_value_scalar> ::= integer
48 /// <init_value_array> ::= {integer ([, integer])}
49 /// ```
50 ///
51 /// The init_value specifies the signal value that shall be used by all subscriber nodes
52 /// until the frame containing the signal is received. The init_value_scalar is used for
53 /// scalar signals and the init_value_array is used for byte array signals. The initial_value for
54 /// byte arrays shall be arranged in big-endian order (i.e. with the most significant byte
55 /// first).
56 ///
57 /// The only way to describe if a signal with size 8 or 16 is a byte array with one or two
58 /// elements or a scalar signal is by analyzing the init_value, i.e. the curly parenthesis are
59 /// very important to distinguish between arrays and scalar values.
60 pub init_value: LdfSignalInitValue,
61
62 /// The published_by specifies the node that is publishing the signal.
63 /// The published_by identifier shall exist in the node identifier set.
64 pub published_by: String,
65
66 /// The subscribed_by specifies the node(s) that is subscribing to the signal.
67 /// The subscribed_by identifiers shall exist in the node identifier set.
68 pub subscribed_by: Vec<String>,
69}
70
71/*
72Signals {
73 Signal1: 10, 0, Master, Slave1 ;
74 Signal2: 10, 0, Master, Slave1 ;
75 Signal3: 10, 0, Slave1, Master ;
76 Signal4: 10, 0, Slave1, Master ;
77 Signal5: 2, 0, Slave1, Master ;
78 Signal6: 1, 0, Slave1, Master ;
79}
80*/
81
82pub fn parse_ldf_signals(s: &str) -> IResult<&str, Vec<LdfSignal>> {
83 // `Signals {` or `Signals{` or ...
84 // - May be any number of spaces before and after the "Signals" tag
85 // - May be any number of spaces before and after the opening curly brace
86 let (s, _) = skip_whitespace(s)?;
87 let (s, _) = tag("Signals")(s)?;
88 let (s, _) = skip_whitespace(s)?;
89 let (s, _) = tag("{")(s)?;
90
91 let mut signals = Vec::new();
92 let mut remaining = s;
93 while !remaining.starts_with('}') {
94 // `Signal1: 10, 0, Master, Slave1 ;` or `Signal1: 10, 0, Master, Slave1;` or ...
95 // - May be any number of spaces before and after the signal name
96 // - May be any number of spaces before and after the colon
97 // - May be any number of spaces before and after the signal size
98 // - May be any number of spaces before and after the comma
99 // - May be any number of spaces before and after the init value
100 // - May be any number of spaces before and after the comma
101 // - May be any number of spaces before and after the published_by node
102 // - May be any number of spaces before and after the comma
103 // - May be any number of spaces before and after the subscribed_by node
104 // - May be any number of spaces before and after the semicolon
105 let (s, _) = skip_whitespace(remaining)?;
106 let (s, signal_name) = take_while(|c: char| c.is_alphanumeric() || c == '_')(s)?;
107 let (s, _) = skip_whitespace(s)?;
108 let (s, _) = tag(":")(s)?;
109 let (s, _) = skip_whitespace(s)?;
110 let (s, signal_size) = take_while(|c: char| c.is_numeric())(s)?;
111 let (s, _) = skip_whitespace(s)?;
112 let (s, _) = tag(",")(s)?;
113 let (s, _) = skip_whitespace(s)?;
114 let (s, init_value) = take_while(|c: char| c.is_numeric())(s)?;
115 let (s, _) = skip_whitespace(s)?;
116 let (s, _) = tag(",")(s)?;
117 let (s, _) = skip_whitespace(s)?;
118 let (s, published_by) = take_while(|c: char| c.is_alphanumeric() || c == '_')(s)?;
119 let (s, _) = skip_whitespace(s)?;
120
121 let (s, symbol) = take_while(|c: char| c == ',' || c == ';')(s)?;
122 let mut subscribed_by = Vec::new();
123 let s = match symbol {
124 "," => {
125 // There is at least one subscribed_by node
126 let (s, subscribed_by_str) = take_until(";")(s)?;
127 subscribed_by = subscribed_by_str.split(',').map(|s| s.trim().to_string()).collect();
128 let (s, _) = tag(";")(s)?;
129 s
130 }
131 ";" => {
132 // There are no subscribed_by nodes
133 s
134 }
135 _ => {
136 // This should not happen, but we can handle it gracefully
137 s
138 }
139 };
140 let (s, _) = skip_whitespace(s)?;
141
142 remaining = s;
143
144 let signal = LdfSignal {
145 name: signal_name.to_string(),
146 signal_size: signal_size.parse().unwrap(),
147 init_value: LdfSignalInitValue::Scalar(init_value.parse().unwrap()),
148 published_by: published_by.to_string(),
149 subscribed_by,
150 };
151
152 signals.push(signal);
153 }
154
155 // `}` or `} ;` or ...
156 // - May be any number of spaces before and after the closing curly brace
157 let (s, _) = skip_whitespace(remaining)?;
158 let (s, _) = tag("}")(s)?;
159
160 Ok((s, signals))
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166
167 #[test]
168 fn test_parse_ldf_signals() {
169 let input = r#"
170 Signals {
171 Signal1: 10, 0, Master, Slave1 , Slave2 ;
172 Signal2: 10, 0, Master, Slave1 ;
173 Signal3: 10, 0, Slave1, Master ;
174 Signal4: 10, 0, Slave1, Master ;
175 Signal5: 2, 0, Slave1, Master ;
176 Signal6: 1, 0, Slave1, Master ;
177 }
178 "#;
179
180 let (_, signals) = parse_ldf_signals(input).unwrap();
181 assert_eq!(signals.len(), 6);
182 assert_eq!(signals[0].name, "Signal1");
183 assert_eq!(signals[0].signal_size, 10);
184 assert_eq!(signals[0].published_by, "Master");
185 assert_eq!(signals[0].subscribed_by, vec!["Slave1", "Slave2"]);
186 assert_eq!(signals[1].name, "Signal2");
187 }
188}