sml_rs/parser/
streaming.rs

1//! Flexible parser that doesn't require dynamic memory allocations.
2//!
3//!
4
5use crate::util::CRC_X25;
6
7use super::{
8    common::{CloseResponse, EndOfSmlMessage, ListEntry, OpenResponse, Signature, Time},
9    octet_string::OctetStr,
10    tlf::{self, Ty, TypeLengthField},
11    OctetStrFormatter, ParseError, ResTy, SmlParse, SmlParseTlf,
12};
13
14/// Incremental parser for SML messages.
15///
16/// See the `parser` module for a discussion of the differences between the different parsers.
17pub struct Parser<'i> {
18    input: &'i [u8],
19    msg_input: &'i [u8],
20    pending_list_entries: u32,
21}
22
23impl<'i> Parser<'i> {
24    /// Create a new Parser from a slice of bytes.
25    pub fn new(input: &'i [u8]) -> Self {
26        Parser {
27            input,
28            msg_input: &[],
29            pending_list_entries: 0,
30        }
31    }
32
33    fn parse_next(&mut self) -> Result<Option<ParseEvent<'i>>, ParseError> {
34        if self.input.is_empty() && self.pending_list_entries == 0 {
35            return Ok(None);
36        }
37
38        Ok(Some(match self.pending_list_entries {
39            0 => {
40                self.msg_input = self.input;
41                let (input, msg) = MessageStart::parse(self.input)?;
42                self.input = input;
43                if let MessageBody::GetListResponse(glr) = &msg.message_body {
44                    self.pending_list_entries = glr.num_vals + 2;
45                } else {
46                    self.pending_list_entries = 1;
47                }
48                ParseEvent::MessageStart(msg)
49            }
50            1 => {
51                let num_bytes_read = self.msg_input.len() - self.input.len();
52
53                let (input, crc) = u16::parse(self.input)?;
54                let (input, _) = EndOfSmlMessage::parse(input)?;
55                self.input = input;
56
57                // validate crc16
58                let digest = CRC_X25
59                    .checksum(&self.msg_input[0..num_bytes_read])
60                    .swap_bytes();
61                if digest != crc {
62                    return Err(ParseError::CrcMismatch);
63                }
64
65                self.pending_list_entries = 0;
66                return self.parse_next();
67            }
68            2 => {
69                let (input, glre) = GetListResponseEnd::parse(self.input)?;
70                self.input = input;
71                self.pending_list_entries = 1;
72                ParseEvent::GetListResponseEnd(glre)
73            }
74            x => {
75                let (input, le) = ListEntry::parse(self.input)?;
76                self.input = input;
77                self.pending_list_entries = x - 1;
78                ParseEvent::ListEntry(le)
79            }
80        }))
81    }
82}
83
84impl<'i> Iterator for Parser<'i> {
85    type Item = Result<ParseEvent<'i>, ParseError>;
86
87    fn next(&mut self) -> Option<Self::Item> {
88        let res = self.parse_next();
89        if res.is_err() {
90            self.input = &[];
91        }
92        match res {
93            Ok(None) => None,
94            Ok(Some(x)) => Some(Ok(x)),
95            Err(e) => Some(Err(e)),
96        }
97    }
98}
99
100/// Event data structure produced by the streaming parser.
101#[derive(Debug)]
102pub enum ParseEvent<'i> {
103    /// Start of an SML Message.
104    MessageStart(MessageStart<'i>),
105    /// End of a GetListResponse message.
106    GetListResponseEnd(GetListResponseEnd<'i>),
107    /// A single data value.
108    ListEntry(ListEntry<'i>),
109}
110
111/// Contains the start of an SML message.
112///
113/// For message types that have a known size (e.g. `OpenResponse`), the `MessageStart` type
114/// contains the whole message. For messages with dynamic size (e.g. `GetListResponse`), the
115/// `MessageStart` type only contains the data read until the start of the dynamically-sized
116/// data. The dynamically-sized elements (`ListEntry` in the case of `GetListResponse`) are
117/// returned as separate events by the parser. For some message types (e.g. `GetListResponse`),
118/// there's a separate event produced when the message has been parsed completely
119/// (`GetListResponseEnd` in case of `GetListResponse`).
120#[derive(PartialEq, Eq, Clone)]
121pub struct MessageStart<'i> {
122    /// transaction identifier
123    pub transaction_id: OctetStr<'i>,
124    /// allows grouping of SML messages
125    pub group_no: u8,
126    /// describes how to handle the Message in case of errors
127    // this should probably be an enum
128    pub abort_on_error: u8,
129    /// main content of the message
130    pub message_body: MessageBody<'i>,
131}
132
133impl<'i> SmlParse<'i> for MessageStart<'i> {
134    fn parse(input: &'i [u8]) -> ResTy<Self> {
135        let (input, tlf) = TypeLengthField::parse(input)?;
136        if tlf.ty != Ty::ListOf || tlf.len != 6 {
137            return Err(ParseError::TlfMismatch("Message"));
138        }
139        let (input, transaction_id) = OctetStr::parse(input)?;
140        let (input, group_no) = u8::parse(input)?;
141        let (input, abort_on_error) = u8::parse(input)?;
142        let (input, message_body) = MessageBody::parse(input)?;
143
144        let val = MessageStart {
145            transaction_id,
146            group_no,
147            abort_on_error,
148            message_body,
149        };
150        Ok((input, val))
151    }
152}
153
154impl<'i> core::fmt::Debug for MessageStart<'i> {
155    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
156        let mut x = f.debug_struct("MessageStart");
157        x.field("transaction_id", &OctetStrFormatter(self.transaction_id));
158        x.field("group_no", &self.group_no);
159        x.field("abort_on_error", &self.abort_on_error);
160        x.field("message_body", &self.message_body);
161        x.finish()
162    }
163}
164
165#[derive(PartialEq, Eq, Clone)]
166/// SML message body
167///
168/// Hint: this type only implements the message types specified by SML that are
169/// used in real-world power meters.
170pub enum MessageBody<'i> {
171    /// `SML_PublicOpen.Res` message
172    OpenResponse(OpenResponse<'i>),
173    /// `SML_PublicClose.Res` message
174    CloseResponse(CloseResponse<'i>),
175    /// Start of the `SML_GetList.Res` message
176    GetListResponse(GetListResponseStart<'i>),
177}
178
179impl<'i> core::fmt::Debug for MessageBody<'i> {
180    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
181        match self {
182            Self::OpenResponse(arg0) => arg0.fmt(f),
183            Self::CloseResponse(arg0) => arg0.fmt(f),
184            Self::GetListResponse(arg0) => arg0.fmt(f),
185        }
186    }
187}
188
189impl<'i> SmlParseTlf<'i> for MessageBody<'i> {
190    fn check_tlf(tlf: &TypeLengthField) -> bool {
191        tlf.ty == tlf::Ty::ListOf && tlf.len == 2
192    }
193
194    fn parse_with_tlf(input: &'i [u8], _tlf: &TypeLengthField) -> ResTy<'i, Self> {
195        let (input, tag) = u32::parse(input)?;
196        match tag {
197            0x00000101 => {
198                let (input, x) = <OpenResponse<'i>>::parse(input)?;
199                Ok((input, MessageBody::OpenResponse(x)))
200            }
201            0x00000201 => {
202                let (input, x) = <CloseResponse<'i>>::parse(input)?;
203                Ok((input, MessageBody::CloseResponse(x)))
204            }
205            0x00000701 => {
206                let (input, x) = <GetListResponseStart<'i>>::parse(input)?;
207                Ok((input, MessageBody::GetListResponse(x)))
208            }
209            _ => Err(ParseError::UnexpectedVariant),
210        }
211    }
212}
213
214#[derive(PartialEq, Eq, Clone)]
215/// Start event of a `GetListResponse` message.
216pub struct GetListResponseStart<'i> {
217    /// identification of the client
218    pub client_id: Option<OctetStr<'i>>,
219    /// identification of the server
220    pub server_id: OctetStr<'i>,
221    /// name of the list
222    pub list_name: Option<OctetStr<'i>>,
223    /// optional sensor time information
224    pub act_sensor_time: Option<Time>,
225    /// number of data values
226    pub num_vals: u32,
227}
228
229impl<'i> crate::parser::SmlParseTlf<'i> for GetListResponseStart<'i> {
230    fn check_tlf(tlf: &TypeLengthField) -> bool {
231        *tlf == crate::parser::tlf::TypeLengthField::new(
232            crate::parser::tlf::Ty::ListOf,
233            7usize as u32,
234        )
235    }
236    fn parse_with_tlf(input: &'i [u8], _tlf: &TypeLengthField) -> ResTy<'i, Self> {
237        let (input, client_id) = <Option<OctetStr<'i>>>::parse(input)?;
238        let (input, server_id) = <OctetStr<'i>>::parse(input)?;
239        let (input, list_name) = <Option<OctetStr<'i>>>::parse(input)?;
240        let (input, act_sensor_time) = <Option<Time>>::parse(input)?;
241        let (input, tlf) = TypeLengthField::parse(input)?;
242        if !matches!(tlf.ty, Ty::ListOf) {
243            return Err(ParseError::TlfMismatch(core::any::type_name::<Self>()));
244        }
245        let val = GetListResponseStart {
246            client_id,
247            server_id,
248            list_name,
249            act_sensor_time,
250            num_vals: tlf.len,
251        };
252        Ok((input, val))
253    }
254}
255
256impl<'i> core::fmt::Debug for GetListResponseStart<'i> {
257    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
258        let mut x = f.debug_struct("GetListResponseStart");
259        if let Some(e) = &self.client_id {
260            x.field("client_id", &OctetStrFormatter(e));
261        }
262        x.field("server_id", &OctetStrFormatter(self.server_id));
263        if let Some(e) = &self.list_name {
264            x.field("list_name", &OctetStrFormatter(e));
265        }
266        if let Some(e) = &self.act_sensor_time {
267            x.field("act_sensor_time", &e);
268        }
269        x.field("num_values", &self.num_vals);
270        x.finish()
271    }
272}
273
274/// End event of a `GetListResponse` message.
275#[derive(PartialEq, Eq, Clone)]
276pub struct GetListResponseEnd<'i> {
277    /// signature of the list - whatever that means?!
278    pub list_signature: Option<Signature<'i>>,
279    /// optional gateway time information
280    pub act_gateway_time: Option<Time>,
281}
282
283impl<'i> crate::parser::SmlParse<'i> for GetListResponseEnd<'i> {
284    fn parse(input: &'i [u8]) -> ResTy<'i, Self> {
285        let (input, list_signature) = <Option<Signature<'i>>>::parse(input)?;
286        let (input, act_gateway_time) = <Option<Time>>::parse(input)?;
287        let val = GetListResponseEnd {
288            list_signature,
289            act_gateway_time,
290        };
291        Ok((input, val))
292    }
293}
294
295impl<'i> core::fmt::Debug for GetListResponseEnd<'i> {
296    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
297        let mut x = f.debug_struct("GetListResponseEnd");
298        if let Some(e) = &self.list_signature {
299            x.field("list_signature", &e);
300        }
301        if let Some(e) = &self.act_gateway_time {
302            x.field("act_gateway_time", &e);
303        }
304        x.finish()
305    }
306}