hackdose_sml_parser/application/
parser.rs

1use byteorder::{BigEndian, ReadBytesExt};
2use std::io::Cursor;
3
4use crate::application::domain::{
5    AnyValue, GetListResponseBody, GetOpenResponseBody, SmlListEntry, SmlMessageEnvelope,
6    SmlMessages,
7};
8
9#[non_exhaustive]
10#[derive(Debug)]
11pub enum ParseError {
12    Unknown,
13}
14
15pub type ParseResult<T> = Result<T, ParseError>;
16
17/// Parse the body of an SML message (omitting header and footer)
18pub fn parse_body(input: &[u8]) -> ParseResult<SmlMessages> {
19    sml_parser::sml_body(input).map_err(|_| ParseError::Unknown)
20}
21
22/// Parse the whole SML message
23pub fn parse_message(input: &[u8]) -> ParseResult<SmlMessages> {
24    sml_parser::sml_messages(input).map_err(|_| ParseError::Unknown)
25}
26
27peg::parser! {
28    grammar sml_parser<'a>() for [u8] {
29
30        pub (crate) rule sml_body() -> SmlMessages =
31            a: (sml_message_envelope())*
32            {
33                SmlMessages {
34                    messages: a
35                }
36            }
37
38        pub (crate) rule sml_messages() -> SmlMessages =
39            header()
40            a: (sml_message_envelope())*
41            footer()
42            {
43                SmlMessages {
44                    messages: a
45                }
46            }
47
48        rule header() -> () =
49            [0x1b] [0x1b] [0x1b] [0x1b] [0x01] [0x01] [0x01] [0x01]
50
51        rule footer() -> () =
52            [0x1b] [0x1b] [0x1b] [0x1b] [0x1a] [0..=255]*<3>
53
54        rule sml_message_envelope() -> SmlMessageEnvelope =
55            [0x76]
56            transaction_id()
57            group_no()
58            abort_on_error()
59            a:sml_message_body()
60            crc()
61            end_of_message()
62            { a }
63
64        rule crc() = [0x63] any_number() any_number()
65
66        // ISKRA MT-631 pads this entry so multiples of 4
67        rule end_of_message() = [0x00]+
68
69        rule sml_message_body() -> SmlMessageEnvelope =
70            get_open_response() /
71            get_list_response() /
72            get_close_response() // and more types
73
74        rule get_open_response() -> SmlMessageEnvelope =
75            [0x72] [0x63] [0x01] [0x01]
76            a: get_open_response_content()
77            {
78                SmlMessageEnvelope::GetOpenResponse(a)
79            }
80
81        rule get_open_response_content() -> GetOpenResponseBody =
82            [0x76]
83            ([0x01] / string())
84            ([0x01] / string())
85            req_file_id: string()
86            server_id: string()
87            optional_sml_time()
88            optional_unsigned()
89            {
90                GetOpenResponseBody {
91                    server_id,
92                    req_file_id
93                }
94            }
95
96        rule optional_sml_time() = ([0x01]) / (sml_time())
97
98        rule sml_time() =
99            [0x72]
100            ([0x62] [0x01] unsigned()) /
101            ([0x62] [0x02] unsigned()) /
102            ([0x62] [0x03] sml_timestamp_local())
103
104        rule sml_timestamp_local() =
105            [0x73]
106                unsigned()
107                signed()
108                signed()
109
110        rule get_close_response() -> SmlMessageEnvelope =
111            [0x72] [0x63] [0x02] [0x01] [0x71]
112            get_close_response_content()
113            {
114                SmlMessageEnvelope::GetCloseResponse
115            }
116
117        rule get_close_response_content() = [0x01] / string()
118
119        rule get_list_response() -> SmlMessageEnvelope =
120            [0x72] [0x63] [0x07] [0x01] [0x77]
121            a: get_list_response_content()
122            {
123                SmlMessageEnvelope::GetListResponse(a)
124            }
125
126        rule list_signature() = [0x01] / string()
127
128        // optional value might be omitted due to bug in ED-300L
129        rule act_gateway_time() = ([0x01]*<0,1>) / (sml_time())
130
131        rule get_list_response_content() -> GetListResponseBody =
132            // clientId
133            string()
134            server_id: string()
135            list_name: string()
136            ([0x01] / sml_time())
137            value_list: list_sml_value() list_signature() act_gateway_time()
138            {
139                GetListResponseBody {
140                    server_id,
141                    list_name,
142                    value_list
143                }
144            }
145
146        rule obscure_prefix_in_get_list_response() =
147            [0x72] [0x62] [0..=255] [0x65] [0..=255] [0..=255] [0..=255] [0..=255]
148
149        rule list_sml_value() -> Vec<SmlListEntry> =
150            prefix: [0x71..=0x7f]
151            value: single_sml_value() * <{
152                let length = prefix - 0x70;
153                length as usize
154            }>
155            { value }
156
157        rule single_sml_value() -> SmlListEntry =
158            [0x77]
159            object_name: string()
160            status: optional_unsigned()
161            value_time: string()
162            unit: optional_unsigned()
163            scaler: scaler()
164            value: value() sml_value_signature()
165            {
166                SmlListEntry {
167                    object_name, status, value_time, unit, scaler, value
168                }
169            }
170
171        rule scaler() -> Option<isize> = optional_signed()
172
173        rule value() -> AnyValue = arbitrary()
174
175        rule sml_value_signature() = [0x01] / string()
176
177        rule arbitrary() -> AnyValue =
178            (v:string() { AnyValue::String(v) }) /
179            (v:signed() { AnyValue::Signed(v as isize) }) /
180            (v:unsigned() { AnyValue::Unsigned(v as usize) })
181
182        pub (crate) rule unsigned() -> usize =
183            prefix: [0x62|0x63|0x64|0x65|0x66|0x67|0x68|0x69]
184            value: (any_number()) * <{
185                let length = prefix - 0x60;
186                length as usize - 1
187            }>
188            {
189                let left_padding = 8+1-(prefix - 0x60) as usize;
190                let mut m = vec![0u8;left_padding];
191                m.append(&mut value.to_vec());
192                let mut rdr = Cursor::new(m);
193                rdr.read_u64::<BigEndian>().unwrap() as usize
194            }
195
196        pub (crate) rule signed() -> isize =
197            prefix: [0x52|0x53|0x54|0x55|0x56|0x57|0x58|0x59]
198            value: (any_number()) * <{
199                let length = prefix - 0x50;
200                length as usize - 1
201            }>
202            {
203                let left_padding = 8+1-(prefix - 0x50) as usize;
204                let pad_byte = if value[0]>=128 { 0xFF } else { 0x00 };
205                let mut m = vec![pad_byte;left_padding];
206                m.append(&mut (value).to_vec());
207                let mut rdr = Cursor::new(m);
208                rdr.read_i64::<BigEndian>().unwrap() as isize
209            }
210
211        rule transaction_id() -> Vec<u8> =
212            string()
213
214        rule group_no() =
215            [0x62] any_number()
216
217        rule abort_on_error() =
218            [0x62] [0x00]
219
220        rule message_checksum() =
221            any_number() any_number() any_number()
222
223        rule any_number() -> u8 =
224            [0..=255]
225
226        rule optional_signed() -> Option<isize> =
227            (v:signed() { Some(v) }) / ([0x01] { None })
228
229        rule optional_unsigned() -> Option<usize> =
230            (v:unsigned() { Some(v) }) / ([0x01] { None })
231
232        rule string() -> Vec<u8> =
233            short_string() / long_string()
234
235        rule short_string() -> Vec<u8> =
236            prefix: [0x01..=0x0f]
237            value: (any_number()) * <{
238                let length = prefix - 0x01;
239                length as usize
240            }>
241            { value }
242
243        rule long_string() -> Vec<u8> =
244            prefix_1: [0x81..=0x83]
245            prefix_2: [0x00..=0x0f]
246            value: any_number() * <{
247                let length = match prefix_1 {
248                    0x81 => 14 + prefix_2,
249                    0x82 => 30 + prefix_2,
250                    0x83 => 46 + prefix_2,
251                    _ => unreachable!()
252                };
253                length as usize
254            }>
255            { value }
256    }
257}
258
259#[cfg(test)]
260mod test {
261    use super::*;
262    #[test]
263    pub fn open() {
264        //
265        let example_open = vec![
266            0x1b, 0x1b, 0x1b, 0x1b, 0x01, 0x01, 0x01, 0x01, // header
267            /* */ 0x76, // List with 6 entries
268            /*      */ 0x05, 0x03, 0x2b, 0x18, 0x0f, // transactionId:
269            /*      */ 0x62, 0x00, // groupNo:
270            /*      */ 0x62, 0x00, //abortOnError:
271            /*      */ 0x72, // messageBody: list with 2 entries
272            /*          */ 0x63, 0x01, 0x01, // getOpenResponse:
273            /*          */ 0x76, // list with 6 entries
274            /*              */ 0x01, // codepage: no value
275            /*              */ 0x01, // clientId: no value
276            /*              */ 0x05, 0x04, 0x03, 0x02, 0x01, // reqFileId:
277            /*              */ 0x0b, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
278            0x0a, /*              */
279            /*              */
280            0x01, // refTime
281            /*              */ 0x01, // smlVersion
282            /*          */ 0x63, 0x49, 0x00, // CRC checksum of this message
283            /*          */ 0x00, // end of this
284            /* */ 0x1b, 0x1b, 0x1b, 0x1b, // Escape Sequenz
285            /* */ 0x1a, 0x00, 0x70, 0xb2, // 1a + padding + CRC (2 bytes)
286        ];
287
288        let result = sml_parser::sml_messages(&example_open);
289
290        assert_eq!(
291            result,
292            Ok(SmlMessages {
293                messages: vec![SmlMessageEnvelope::GetOpenResponse(GetOpenResponseBody {
294                    server_id: vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a],
295                    req_file_id: vec![0x04, 0x03, 0x02, 0x01]
296                })]
297            })
298        )
299    }
300
301    #[test]
302    pub fn get_list_response_body() {
303        //
304        let example_list = vec![
305            /* */ 0x76, //
306            /*      */ 0x05, 0x01, 0xD3, 0xD7, 0xBB, //
307            /*      */ 0x62, 0x00, //
308            /*      */ 0x62, 0x00, //
309            /*      */ 0x72, //
310            /*          */ 0x63, 0x07, 0x01, // getListResponse
311            /*          */ 0x77, //
312            /*              */ 0x01, // clientId / optional
313            /*              */ 0x0B, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
314            0x0a, // serverId
315            /*              */ 0x07, 0x01, 0x00, 0x62, 0x0A, 0xFF, 0xFF, // listName
316            /*              */ 0x72, // actSensorTime / optional
317            /*                  */ 0x62, 0x01, // choice: secIndex
318            /*                  */ 0x65, 0x01, 0x8A, 0x4D, 0x15, // secIndex (uptime)
319            /*              */ 0x72, // valList
320            /*                  */ 0x77, // SML_ListEntry
321            /*                      */ 0x07, 0x81, 0x81, 0xC7, 0x82, 0x03,
322            0xFF, // objName
323            /*                      */ 0x01, // status
324            /*                      */ 0x01, // valTime
325            /*                      */ 0x01, // unit
326            /*                      */ 0x01, // scaler
327            /*                      */ 0x04, 0x49, 0x53,
328            0x4B, // value -- Herstelleridentifikation (ISK)
329            /*                      */ 0x01, // valueSignature / optional
330            /*                  */ 0x77, // SML_ListEntry
331            /*                      */ 0x07, 0x01, 0x00, 0x01, 0x08, 0x00,
332            0xFF, // objName
333            /*                      */ 0x65, 0x00, 0x00, 0x01, 0x82, // status / optional
334            /*                      */ 0x01, // valTime / optional
335            /*                      */ 0x62, 0x1E, // unit / optional
336            /*                      */ 0x52, 0xFF, // scaler / optional
337            /*                      */ 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
338            0x00, // Gesamtverbrauch
339            /*                      */ 0x01, // valueSignature / optional
340            /*                  */ 0x01, // listSignature / optional
341            /*                  */ 0x01, // actGatewayTime / optional
342            /*      */ 0x63, 0xC6, 0x12, // crc
343            /*      */ 0x00, // end of message
344        ];
345
346        let result = sml_parser::sml_body(&example_list);
347
348        assert_eq!(
349            result,
350            Ok(SmlMessages {
351                messages: vec![SmlMessageEnvelope::GetListResponse(GetListResponseBody {
352                    server_id: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
353                    list_name: vec![1, 0, 98, 10, 255, 255],
354                    value_list: vec![
355                        SmlListEntry {
356                            object_name: vec![129, 129, 199, 130, 3, 255],
357                            status: None,
358                            value_time: vec![],
359                            unit: None,
360                            scaler: None,
361                            value: AnyValue::String(vec![73, 83, 75])
362                        },
363                        SmlListEntry {
364                            object_name: vec![1, 0, 1, 8, 0, 255],
365                            status: Some(386),
366                            value_time: vec![],
367                            unit: Some(30),
368                            scaler: Some(-1),
369                            value: AnyValue::Signed(0)
370                        }
371                    ]
372                })]
373            })
374        )
375    }
376
377    #[test]
378    pub fn get_close_response() {
379        let example_close = vec![
380            0x1b, 0x1b, 0x1b, 0x1b, 0x01, 0x01, 0x01, 0x01, // header
381            /*  */
382            0x76, //
383            /*      */ 0x05, 0x03, 0x2b, 0x18, 0x11, // transactionId:
384            /*      */ 0x62, 0x00, // #groupNo:
385            /*      */ 0x62, 0x00, // #abortOnError:
386            /*      */ 0x72, //	messageBody:
387            /*          */ 0x63, 0x02, 0x01, //	getCloseResponse:
388            /*          */ 0x71, //
389            /*              */ 0x01, // no value
390            /*      */ 0x63, 0xfa, 0x36, // CRC
391            /*      */ 0x00, //
392            /* */ 0x1b, 0x1b, 0x1b, 0x1b, // escape sequence
393            /* */ 0x1a, 0x00, 0x70, 0xb2, // 1a + padding + CRC (2 bytes)
394        ];
395        let result = sml_parser::sml_messages(&example_close);
396
397        assert_eq!(
398            result,
399            Ok(SmlMessages {
400                messages: vec![SmlMessageEnvelope::GetCloseResponse]
401            })
402        )
403    }
404
405    #[test]
406    pub fn example_with_exotic_number_types() {
407        let bytes = vec![
408            0x1b, 0x1b, 0x1b, 0x1b, 0x01, 0x01, 0x01, 0x01, 0x76, 0x07, 0x00, 0x11, 0x06, 0x33,
409            0x10, 0x11, 0x62, 0x00, 0x62, 0x00, 0x72, 0x63, 0x01, 0x01, 0x76, 0x01, 0x01, 0x07,
410            0x00, 0x11, 0x04, 0x5d, 0x05, 0x5b, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
411            0x93, 0xa2, 0xc7, 0x01, 0x01, 0x63, 0xc0, 0xd3, 0x00, 0x76, 0x07, 0x00, 0x11, 0x06,
412            0x33, 0x10, 0x12, 0x62, 0x00, 0x62, 0x00, 0x72, 0x63, 0x07, 0x01, 0x77, 0x01, 0x0b,
413            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0xa2, 0xc7, 0x07, 0x01, 0x00, 0x62,
414            0x0a, 0xff, 0xff, 0x72, 0x62, 0x01, 0x65, 0x04, 0x5d, 0x00, 0xd1, 0x79, 0x77, 0x07,
415            0x81, 0x81, 0xc7, 0x82, 0x03, 0xff, 0x01, 0x01, 0x01, 0x01, 0x04, 0x45, 0x4d, 0x48,
416            0x01, 0x77, 0x07, 0x01, 0x00, 0x00, 0x00, 0x09, 0xff, 0x01, 0x01, 0x01, 0x01, 0x0b,
417            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0xa2, 0xc7, 0x01, 0x77, 0x07, 0x01,
418            0x00, 0x01, 0x08, 0x00, 0xff, 0x64, 0x01, 0x02, 0x82, 0x01, 0x62, 0x1e, 0x52, 0x03,
419            0x56, 0x00, 0x00, 0x00, 0x0e, 0x0d, 0x01, 0x77, 0x07, 0x01, 0x00, 0x02, 0x08, 0x00,
420            0xff, 0x64, 0x01, 0x02, 0x82, 0x01, 0x62, 0x1e, 0x52, 0x03, 0x56, 0x00, 0x00, 0x00,
421            0x14, 0xc1, 0x01, 0x77, 0x07, 0x01, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0x01, 0x62,
422            0x1e, 0x52, 0x03, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x77, 0x07, 0x01, 0x00,
423            0x02, 0x08, 0x01, 0xff, 0x01, 0x01, 0x62, 0x1e, 0x52, 0x03, 0x56, 0x00, 0x00, 0x00,
424            0x14, 0xc1, 0x01, 0x77, 0x07, 0x01, 0x00, 0x01, 0x08, 0x02, 0xff, 0x01, 0x01, 0x62,
425            0x1e, 0x52, 0x03, 0x56, 0x00, 0x00, 0x00, 0x0e, 0x0d, 0x01, 0x77, 0x07, 0x01, 0x00,
426            0x02, 0x08, 0x02, 0xff, 0x01, 0x01, 0x62, 0x1e, 0x52, 0x03, 0x56, 0x00, 0x00, 0x00,
427            0x00, 0x00, 0x01, 0x77, 0x07, 0x81, 0x81, 0xc7, 0x82, 0x05, 0xff, 0x01, 0x01, 0x01,
428            0x01, 0x83, 0x02, 0x65, 0xdc, 0xe7, 0x5e, 0xa7, 0x7a, 0xdf, 0x65, 0x1c, 0xc3, 0xc3,
429            0xde, 0x43, 0xe2, 0xf6, 0xb2, 0x72, 0x0d, 0x78, 0x0b, 0xd2, 0xf0, 0x54, 0xa4, 0xc7,
430            0x8c, 0xc3, 0x8c, 0xfc, 0x42, 0xb0, 0x6e, 0xa5, 0x27, 0xbf, 0xe0, 0xfc, 0x51, 0x4a,
431            0xb8, 0x6f, 0x83, 0x03, 0x0f, 0x54, 0x1b, 0x4f, 0x87, 0x01, 0x01, 0x01, 0x63, 0xaa,
432            0x28, 0x00, 0x76, 0x07, 0x00, 0x11, 0x06, 0x33, 0x10, 0x15, 0x62, 0x00, 0x62, 0x00,
433            0x72, 0x63, 0x02, 0x01, 0x71, 0x01, 0x63, 0x0b, 0x74, 0x00, 0x1b, 0x1b, 0x1b, 0x1b,
434            0x1a, 0x00, 0x0b, 0xc6,
435        ];
436        let result = sml_parser::sml_messages(&bytes);
437
438        assert_eq!(result.is_ok(), true)
439    }
440
441    #[test]
442    pub fn reads_8_bit_signed() {
443        let bytes = vec![0x52, 0x02];
444
445        let result = sml_parser::signed(&bytes);
446        assert_eq!(result, Ok(2isize));
447    }
448
449    #[test]
450    pub fn reads_negative_8_bit_signed() {
451        let bytes = vec![0x52, 0xFE];
452
453        let result = sml_parser::signed(&bytes);
454        assert_eq!(result, Ok(-2isize));
455    }
456
457    #[test]
458    pub fn reads_32_bit_signed() {
459        let bytes = vec![0x55, 0x00, 0x00, 0x00, 0x01];
460
461        let result = sml_parser::signed(&bytes);
462        assert_eq!(result, Ok(1isize));
463    }
464
465    #[test]
466    pub fn reads_negative_32_bit_signed() {
467        let bytes = vec![0x55, 0xFF, 0xFF, 0xFF, 0xFF];
468
469        let result = sml_parser::signed(&bytes);
470        assert_eq!(result, Ok(-1isize));
471    }
472
473    #[test]
474    pub fn reads_positive_56_bit_unsigned() {
475        let bytes = vec![0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01];
476
477        let result = sml_parser::unsigned(&bytes);
478        assert_eq!(result, Ok(1usize));
479    }
480
481    #[test]
482    pub fn reads_positive_56_bit_signed() {
483        let bytes = vec![0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01];
484
485        let result = sml_parser::signed(&bytes);
486        assert_eq!(result, Ok(1isize));
487    }
488
489    #[test]
490
491    pub fn reads_negative_56_bit_signed() {
492        let bytes = vec![0x58, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
493
494        let result = sml_parser::signed(&bytes);
495        assert_eq!(result, Ok(-1isize));
496    }
497
498    #[test]
499    pub fn iskra_mt631() {
500        let bytes = vec![
501            0x1B, 0x1B, 0x1B, 0x1B, 0x01, 0x01, 0x01, 0x01, 0x76, 0x05, 0x13, 0x31, 0xB4, 0xC4,
502            0x62, 0x00, 0x62, 0x00, 0x72, 0x63, 0x01, 0x01, 0x76, 0x01, 0x01, 0x05, 0x06, 0x65,
503            0xE6, 0xEC, 0x0B, 0x0A, 0x01, 0x49, 0x53, 0x4B, 0x00, 0x04, 0x54, 0xA9, 0x5F, 0x72,
504            0x62, 0x01, 0x65, 0x06, 0x65, 0xE8, 0xA5, 0x62, 0x01, 0x63, 0xEB, 0x95, 0x00, 0x76,
505            0x05, 0x13, 0x31, 0xB4, 0xC5, 0x62, 0x00, 0x62, 0x00, 0x72, 0x63, 0x07, 0x01, 0x77,
506            0x01, 0x0B, 0x0A, 0x01, 0x49, 0x53, 0x4B, 0x00, 0x04, 0x54, 0xA9, 0x5F, 0x07, 0x01,
507            0x00, 0x62, 0x0A, 0xFF, 0xFF, 0x72, 0x62, 0x01, 0x65, 0x06, 0x65, 0xE8, 0xA5, 0x76,
508            0x77, 0x07, 0x01, 0x00, 0x60, 0x32, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x49,
509            0x53, 0x4B, 0x01, 0x77, 0x07, 0x01, 0x00, 0x60, 0x01, 0x00, 0xFF, 0x01, 0x01, 0x01,
510            0x01, 0x0B, 0x0A, 0x01, 0x49, 0x53, 0x4B, 0x00, 0x04, 0x54, 0xA9, 0x5F, 0x01, 0x77,
511            0x07, 0x01, 0x00, 0x01, 0x08, 0x00, 0xFF, 0x65, 0x00, 0x1C, 0x00, 0x04, 0x01, 0x62,
512            0x1E, 0x52, 0xFF, 0x65, 0x0A, 0x07, 0x44, 0xF5, 0x01, 0x77, 0x07, 0x01, 0x00, 0x01,
513            0x08, 0x01, 0xFF, 0x01, 0x01, 0x62, 0x1E, 0x52, 0xFF, 0x63, 0xB3, 0x63, 0x01, 0x77,
514            0x07, 0x01, 0x00, 0x01, 0x08, 0x02, 0xFF, 0x01, 0x01, 0x62, 0x1E, 0x52, 0xFF, 0x65,
515            0x0A, 0x06, 0x91, 0x92, 0x01, 0x77, 0x07, 0x01, 0x00, 0x10, 0x07, 0x00, 0xFF, 0x01,
516            0x01, 0x62, 0x1B, 0x52, 0x00, 0x52, 0x00, 0x01, 0x01, 0x01, 0x63, 0xC5, 0x24, 0x00,
517            0x76, 0x05, 0x13, 0x31, 0xB4, 0xC6, 0x62, 0x00, 0x62, 0x00, 0x72, 0x63, 0x02, 0x01,
518            0x71, 0x01, 0x63, 0x98, 0x98, 0x00, 0x1B, 0x1B, 0x1B, 0x1B, 0x1A, 0x00, 0x1A, 0xB1,
519        ];
520
521        let bytes2 = vec![
522            0x1B, 0x1B, 0x1B, 0x1B, 0x01, 0x01, 0x01, 0x01, 0x76, 0x05, 0x13, 0x31, 0xB4, 0xC7,
523            0x62, 0x00, 0x62, 0x00, 0x72, 0x63, 0x01, 0x01, 0x76, 0x01, 0x01, 0x05, 0x06, 0x65,
524            0xE6, 0xED, 0x0B, 0x0A, 0x01, 0x49, 0x53, 0x4B, 0x00, 0x04, 0x54, 0xA9, 0x5F, 0x72,
525            0x62, 0x01, 0x65, 0x06, 0x65, 0xE8, 0xA6, 0x62, 0x01, 0x63, 0x9B, 0x24, 0x00, 0x76,
526            0x05, 0x13, 0x31, 0xB4, 0xC8, 0x62, 0x00, 0x62, 0x00, 0x72, 0x63, 0x07, 0x01, 0x77,
527            0x01, 0x0B, 0x0A, 0x01, 0x49, 0x53, 0x4B, 0x00, 0x04, 0x54, 0xA9, 0x5F, 0x07, 0x01,
528            0x00, 0x62, 0x0A, 0xFF, 0xFF, 0x72, 0x62, 0x01, 0x65, 0x06, 0x65, 0xE8, 0xA6, 0x76,
529            0x77, 0x07, 0x01, 0x00, 0x60, 0x32, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x49,
530            0x53, 0x4B, 0x01, 0x77, 0x07, 0x01, 0x00, 0x60, 0x01, 0x00, 0xFF, 0x01, 0x01, 0x01,
531            0x01, 0x0B, 0x0A, 0x01, 0x49, 0x53, 0x4B, 0x00, 0x04, 0x54, 0xA9, 0x5F, 0x01, 0x77,
532            0x07, 0x01, 0x00, 0x01, 0x08, 0x00, 0xFF, 0x65, 0x00, 0x1C, 0x00, 0x04, 0x01, 0x62,
533            0x1E, 0x52, 0xFF, 0x65, 0x0A, 0x07, 0x44, 0xF5, 0x01, 0x77, 0x07, 0x01, 0x00, 0x01,
534            0x08, 0x01, 0xFF, 0x01, 0x01, 0x62, 0x1E, 0x52, 0xFF, 0x63, 0xB3, 0x63, 0x01, 0x77,
535            0x07, 0x01, 0x00, 0x01, 0x08, 0x02, 0xFF, 0x01, 0x01, 0x62, 0x1E, 0x52, 0xFF, 0x65,
536            0x0A, 0x06, 0x91, 0x92, 0x01, 0x77, 0x07, 0x01, 0x00, 0x10, 0x07, 0x00, 0xFF, 0x01,
537            0x01, 0x62, 0x1B, 0x52, 0x00, 0x52, 0x00, 0x01, 0x01, 0x01, 0x63, 0x59, 0xD0, 0x00,
538            0x76, 0x05, 0x13, 0x31, 0xB4, 0xC9, 0x62, 0x00, 0x62, 0x00, 0x72, 0x63, 0x02, 0x01,
539            0x71, 0x01, 0x63, 0xD4, 0x84, 0x00, 0x1B, 0x1B, 0x1B, 0x1B, 0x1A, 0x00, 0x28, 0xCE,
540        ];
541
542        let bytes3 = vec![
543            0x1B, 0x1B, 0x1B, 0x1B, 0x01, 0x01, 0x01, 0x01, 0x76, 0x05, 0x13, 0x31, 0xB4, 0xCA,
544            0x62, 0x00, 0x62, 0x00, 0x72, 0x63, 0x01, 0x01, 0x76, 0x01, 0x01, 0x05, 0x06, 0x65,
545            0xE6, 0xEE, 0x0B, 0x0A, 0x01, 0x49, 0x53, 0x4B, 0x00, 0x04, 0x54, 0xA9, 0x5F, 0x72,
546            0x62, 0x01, 0x65, 0x06, 0x65, 0xE8, 0xA7, 0x62, 0x01, 0x63, 0x6E, 0xE2, 0x00, 0x76,
547            0x05, 0x13, 0x31, 0xB4, 0xCB, 0x62, 0x00, 0x62, 0x00, 0x72, 0x63, 0x07, 0x01, 0x77,
548            0x01, 0x0B, 0x0A, 0x01, 0x49, 0x53, 0x4B, 0x00, 0x04, 0x54, 0xA9, 0x5F, 0x07, 0x01,
549            0x00, 0x62, 0x0A, 0xFF, 0xFF, 0x72, 0x62, 0x01, 0x65, 0x06, 0x65, 0xE8, 0xA7, 0x76,
550            0x77, 0x07, 0x01, 0x00, 0x60, 0x32, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x49,
551            0x53, 0x4B, 0x01, 0x77, 0x07, 0x01, 0x00, 0x60, 0x01, 0x00, 0xFF, 0x01, 0x01, 0x01,
552            0x01, 0x0B, 0x0A, 0x01, 0x49, 0x53, 0x4B, 0x00, 0x04, 0x54, 0xA9, 0x5F, 0x01, 0x77,
553            0x07, 0x01, 0x00, 0x01, 0x08, 0x00, 0xFF, 0x65, 0x00, 0x1C, 0x00, 0x04, 0x01, 0x62,
554            0x1E, 0x52, 0xFF, 0x65, 0x0A, 0x07, 0x44, 0xF5, 0x01, 0x77, 0x07, 0x01, 0x00, 0x01,
555            0x08, 0x01, 0xFF, 0x01, 0x01, 0x62, 0x1E, 0x52, 0xFF, 0x63, 0xB3, 0x63, 0x01, 0x77,
556            0x07, 0x01, 0x00, 0x01, 0x08, 0x02, 0xFF, 0x01, 0x01, 0x62, 0x1E, 0x52, 0xFF, 0x65,
557            0x0A, 0x06, 0x91, 0x92, 0x01, 0x77, 0x07, 0x01, 0x00, 0x10, 0x07, 0x00, 0xFF, 0x01,
558            0x01, 0x62, 0x1B, 0x52, 0x00, 0x52, 0x00, 0x01, 0x01, 0x01, 0x63, 0x38, 0x51, 0x00,
559            0x76, 0x05, 0x13, 0x31, 0xB4, 0xCC, 0x62, 0x00, 0x62, 0x00, 0x72, 0x63, 0x02, 0x01,
560            0x71, 0x01, 0x63, 0x10, 0x8F, 0x00, 0x1B, 0x1B, 0x1B, 0x1B, 0x1A, 0x00, 0x58, 0xD8,
561        ];
562
563        let bytes4 = vec![
564            0x1B, 0x1B, 0x1B, 0x1B, 0x01, 0x01, 0x01, 0x01, 0x76, 0x05, 0x13, 0x31, 0xB4, 0xCD,
565            0x62, 0x00, 0x62, 0x00, 0x72, 0x63, 0x01, 0x01, 0x76, 0x01, 0x01, 0x05, 0x06, 0x65,
566            0xE6, 0xEF, 0x0B, 0x0A, 0x01, 0x49, 0x53, 0x4B, 0x00, 0x04, 0x54, 0xA9, 0x5F, 0x72,
567            0x62, 0x01, 0x65, 0x06, 0x65, 0xE8, 0xA8, 0x62, 0x01, 0x63, 0xBF, 0x4D, 0x00, 0x76,
568            0x05, 0x13, 0x31, 0xB4, 0xCE, 0x62, 0x00, 0x62, 0x00, 0x72, 0x63, 0x07, 0x01, 0x77,
569            0x01, 0x0B, 0x0A, 0x01, 0x49, 0x53, 0x4B, 0x00, 0x04, 0x54, 0xA9, 0x5F, 0x07, 0x01,
570            0x00, 0x62, 0x0A, 0xFF, 0xFF, 0x72, 0x62, 0x01, 0x65, 0x06, 0x65, 0xE8, 0xA8, 0x76,
571            0x77, 0x07, 0x01, 0x00, 0x60, 0x32, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x49,
572            0x53, 0x4B, 0x01, 0x77, 0x07, 0x01, 0x00, 0x60, 0x01, 0x00, 0xFF, 0x01, 0x01, 0x01,
573            0x01, 0x0B, 0x0A, 0x01, 0x49, 0x53, 0x4B, 0x00, 0x04, 0x54, 0xA9, 0x5F, 0x01, 0x77,
574            0x07, 0x01, 0x00, 0x01, 0x08, 0x00, 0xFF, 0x65, 0x00, 0x1C, 0x00, 0x04, 0x01, 0x62,
575            0x1E, 0x52, 0xFF, 0x65, 0x0A, 0x07, 0x44, 0xF5, 0x01, 0x77, 0x07, 0x01, 0x00, 0x01,
576            0x08, 0x01, 0xFF, 0x01, 0x01, 0x62, 0x1E, 0x52, 0xFF, 0x63, 0xB3, 0x63, 0x01, 0x77,
577            0x07, 0x01, 0x00, 0x01, 0x08, 0x02, 0xFF, 0x01, 0x01, 0x62, 0x1E, 0x52, 0xFF, 0x65,
578            0x0A, 0x06, 0x91, 0x92, 0x01, 0x77, 0x07, 0x01, 0x00, 0x10, 0x07, 0x00, 0xFF, 0x01,
579            0x01, 0x62, 0x1B, 0x52, 0x00, 0x52, 0x00, 0x01, 0x01, 0x01, 0x63, 0xAB, 0x25, 0x00,
580            0x76, 0x05, 0x13, 0x31, 0xB4, 0xCF, 0x62, 0x00, 0x62, 0x00, 0x72, 0x63, 0x02, 0x01,
581            0x71, 0x01, 0x63, 0xA3, 0x71, 0x00, 0x1B, 0x1B, 0x1B, 0x1B, 0x1A, 0x00, 0x1B, 0xC4,
582        ];
583
584        let result = sml_parser::sml_messages(&bytes);
585        let result2 = sml_parser::sml_messages(&bytes2);
586        let result3 = sml_parser::sml_messages(&bytes3);
587        let result4 = sml_parser::sml_messages(&bytes4);
588
589        assert!(result.is_ok());
590        assert!(result2.is_ok());
591        assert!(result3.is_ok());
592        assert!(result4.is_ok());
593    }
594
595    #[test]
596    pub fn iskra_mt631_without_pin() {
597        let bytes = vec![
598            0x1B, 0x1B, 0x1B, 0x1B, 0x01, 0x01, 0x01, 0x01, 0x76, 0x05, 0x13, 0x00, 0x88, 0x91,
599            0x62, 0x00, 0x62, 0x00, 0x72, 0x63, 0x01, 0x01, 0x76, 0x01, 0x01, 0x05, 0x06, 0x55,
600            0x82, 0xDB, 0x0B, 0x0A, 0x01, 0x49, 0x53, 0x4B, 0x00, 0x04, 0x54, 0xA9, 0x5F, 0x72,
601            0x62, 0x01, 0x65, 0x06, 0x55, 0x84, 0x8E, 0x62, 0x01, 0x63, 0xA4, 0xFF, 0x00, 0x76,
602            0x05, 0x13, 0x00, 0x88, 0x92, 0x62, 0x00, 0x62, 0x00, 0x72, 0x63, 0x07, 0x01, 0x77,
603            0x01, 0x0B, 0x0A, 0x01, 0x49, 0x53, 0x4B, 0x00, 0x04, 0x54, 0xA9, 0x5F, 0x07, 0x01,
604            0x00, 0x62, 0x0A, 0xFF, 0xFF, 0x72, 0x62, 0x01, 0x65, 0x06, 0x55, 0x84, 0x8E, 0x75,
605            0x77, 0x07, 0x01, 0x00, 0x60, 0x32, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x49,
606            0x53, 0x4B, 0x01, 0x77, 0x07, 0x01, 0x00, 0x60, 0x01, 0x00, 0xFF, 0x01, 0x01, 0x01,
607            0x01, 0x0B, 0x0A, 0x01, 0x49, 0x53, 0x4B, 0x00, 0x04, 0x54, 0xA9, 0x5F, 0x01, 0x77,
608            0x07, 0x01, 0x00, 0x01, 0x08, 0x00, 0xFF, 0x65, 0x00, 0x1C, 0x00, 0x04, 0x01, 0x62,
609            0x1E, 0x52, 0x03, 0x63, 0x41, 0x92, 0x01, 0x77, 0x07, 0x01, 0x00, 0x01, 0x08, 0x01,
610            0xFF, 0x01, 0x01, 0x62, 0x1E, 0x52, 0x03, 0x62, 0x04, 0x01, 0x77, 0x07, 0x01, 0x00,
611            0x01, 0x08, 0x02, 0xFF, 0x01, 0x01, 0x62, 0x1E, 0x52, 0x03, 0x63, 0x41, 0x8E, 0x01,
612            0x01, 0x01, 0x63, 0x52, 0x4D, 0x00, 0x76, 0x05, 0x13, 0x00, 0x88, 0x93, 0x62, 0x00,
613            0x62, 0x00, 0x72, 0x63, 0x02, 0x01, 0x71, 0x01, 0x63, 0x33, 0xF4, 0x00, 0x00, 0x00,
614            0x1B, 0x1B, 0x1B, 0x1B, 0x1A, 0x02, 0x40, 0x0D,
615        ];
616        let result = sml_parser::sml_messages(&bytes);
617        assert!(result.is_ok());
618    }
619}