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