orouter_serial/host/
mod.rs

1//! Wrap messages
2//!
3//! Message send between host (computer, phone) connected using either USB or BLE
4//!
5//! These are not part of Overline specification
6//!
7//! When application wants to send messages to overline node, it it supposed to use this library
8//! for correct communication - especially
9//! [`Message::as_frames`](enum.Message.html#method.as_frames)
10//! method is crucial for communication to work as it makes sure the messages is COBS encoded
11//! AND split to maximum size frames suitable for the node's serial interface
12use core::convert::{TryFrom, TryInto};
13#[cfg(feature = "std")]
14use core::fmt;
15#[cfg(feature = "std")]
16use core::str::FromStr;
17use heapless::Vec;
18
19pub mod codec;
20
21const COBS_SENTINEL: u8 = 0x00;
22#[cfg(feature = "std")]
23pub const DEFAULT_MAX_MESSAGE_QUEUE_LENGTH: usize = 3;
24#[cfg(not(feature = "std"))]
25pub const DEFAULT_MAX_MESSAGE_QUEUE_LENGTH: usize = 3;
26pub const RAWIQ_DATA_LENGTH: usize = 2 * 16_536; // 2048 u16s
27pub const RAWIQ_SAMPLING_FREQ: u32 = 65000; // hertz
28
29/// Computed as
30///
31/// ```ignore - not a test
32/// 1+longest_message_length => (now RawIq length with max data)
33/// +
34/// 1+ceil(<previous result>/254) = COBS worst overhead
35/// +
36/// 1 = COBS sentinel (0x00 in our case)
37/// ---
38/// <result>
39/// ```
40///
41pub const fn calculate_cobs_overhead(unecoded_message_size: usize) -> usize {
42    const COBS_OVERHEAD_MAXIMUM: usize = 254;
43    // message type
44    1 +
45        // message size
46        unecoded_message_size +
47        // constant ceil(x / y) can be written as (x+y-1) / y
48        1 + (unecoded_message_size + COBS_OVERHEAD_MAXIMUM - 1) / COBS_OVERHEAD_MAXIMUM +
49        // COBS sentinel
50        1
51}
52
53#[cfg(feature = "std")]
54pub const MAX_MESSAGE_LENGTH: usize = calculate_cobs_overhead(RAWIQ_DATA_LENGTH + 1);
55#[cfg(not(feature = "std"))]
56pub const MAX_MESSAGE_LENGTH: usize = calculate_cobs_overhead(255);
57pub type HostMessageVec = Vec<u8, MAX_MESSAGE_LENGTH>;
58
59#[derive(PartialEq)]
60#[cfg_attr(feature = "std", derive(Debug))]
61pub enum Error {
62    BufferFull,
63    BufferLengthNotSufficient,
64    MalformedMessage,
65    MessageQueueFull,
66    CannotAppendCommand,
67    CodecError(codec::CodecError),
68    CobsEncodeError,
69    CannotParseConfigNetwork,
70}
71
72impl From<codec::CodecError> for Error {
73    fn from(e: codec::CodecError) -> Error {
74        Error::CodecError(e)
75    }
76}
77
78#[derive(Clone, PartialEq)]
79#[cfg_attr(feature = "std", derive(Debug))]
80#[repr(u8)]
81pub enum StatusCode {
82    FrameReceived = 1,
83    CommandReceived = 2,
84    ErrUnknownCommmandReceived = 3,
85    ErrBusyLoraTransmitting = 4,
86    ErrMessageQueueFull = 5,
87    RadioNotConfigured = 6,
88}
89
90impl TryFrom<u8> for StatusCode {
91    type Error = &'static str;
92
93    fn try_from(value: u8) -> Result<Self, Self::Error> {
94        match value {
95            1 => Ok(StatusCode::FrameReceived),
96            2 => Ok(StatusCode::CommandReceived),
97            3 => Ok(StatusCode::ErrUnknownCommmandReceived),
98            4 => Ok(StatusCode::ErrBusyLoraTransmitting),
99            5 => Ok(StatusCode::ErrMessageQueueFull),
100            6 => Ok(StatusCode::RadioNotConfigured),
101            _ => Err("Unknown StatusCode"),
102        }
103    }
104}
105#[cfg(feature = "std")]
106impl fmt::Display for StatusCode {
107    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108        match *self {
109            StatusCode::FrameReceived => write!(f, "Single serial frame was successfuly received"),
110            StatusCode::CommandReceived => write!(f, "Command was successfully received"),
111            StatusCode::ErrUnknownCommmandReceived => write!(f, "Error: unknown command type"),
112            StatusCode::ErrBusyLoraTransmitting => write!(
113                f,
114                "Error: cannot execute sent command - radio is currently busy transmitting"
115            ),
116            StatusCode::ErrMessageQueueFull => write!(
117                f,
118                "Transmit queue is full, try sending SendData later again"
119            ),
120            StatusCode::RadioNotConfigured => write!(f, "Error: radio is not configured"),
121        }
122    }
123}
124
125/// Possible commands send over host protocol
126///
127/// This enum contains both messages send exlusively to node or exclusively to host
128#[derive(PartialEq)]
129pub enum Message {
130    /// Host sending data to node instructing it to broadcast it to the wireless network
131    SendData {
132        data: Vec<u8, { crate::MAX_LORA_PAYLOAD_LENGTH }>,
133    },
134    /// Node sending data to host
135    ReceiveData {
136        data: Vec<u8, { crate::MAX_LORA_PAYLOAD_LENGTH }>,
137    },
138    /// Host is recongifuring the node
139    Configure {
140        region: u8,
141        spreading_factor: u8,
142        network: u16,
143    },
144    /// Host requesting the node status
145    ReportRequest,
146    /// Node reporting information to host
147    Report {
148        /// BE encoded
149        sn: u32,
150        /// BE encoded
151        version_data: Vec<u8, 9>,
152        region: u8,
153        spreading_factor: u8,
154        receive_queue_size: u8,
155        transmit_queue_size: u8,
156        network: u16,
157    },
158    /// Node reporting some error state to host
159    Status { code: StatusCode },
160    /// Firmware upgrade will follow
161    UpgradeFirmwareRequest,
162    /// Set current time
163    SetTimestamp { timestamp: u64 },
164    /// Get rawIq data
165    GetRawIq,
166    /// Node returns raw IQ data to host
167    #[cfg(feature = "std")]
168    RawIq { data: Vec<u8, RAWIQ_DATA_LENGTH> },
169}
170
171// this is not derived with cfg_attr(feature = "std" because we want the fields to be formatted as
172// hex
173#[cfg(feature = "std")]
174impl fmt::Debug for Message {
175    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
176        match self {
177            Message::SendData { data } => write!(f, "SendData {{ data: {:02x?} }}", data),
178            Message::ReceiveData { data } => write!(f, "ReceiveData {{ data: {:02x?} }}", data),
179            Message::Configure { region, spreading_factor, network } => write!(f, "Configure {{ region: {:02x?}, spreading_factor: {:?}, network: {:02x?} }}", region, spreading_factor, network.to_be_bytes()),
180            Message::ReportRequest => write!(f, "ReportRequest"),
181            Message::Report {
182                sn,
183                version_data,
184                region,
185                spreading_factor,
186                receive_queue_size,
187                transmit_queue_size,
188                network,
189            } => write!(f, "Report {{ sn: {:?}, version_data: {:02x?}, region: {:02x?}, spreading_factor: {:?}, receive_queue_size: {:?}, transmit_queue_size: {:?}, network: {:02x?}", sn, version_data, region, spreading_factor, receive_queue_size, transmit_queue_size, network.to_be_bytes()),
190            Message::Status { code } => write!(f, "Status({:?})", code),
191            Message::UpgradeFirmwareRequest => write!(f, "UpgradeFirmwareRequest"),
192            Message::SetTimestamp { timestamp } => write!(f, "SetTimestamp({:?})", timestamp),
193            Message::GetRawIq => write!(f, "GetRawIq"),
194            #[cfg(feature = "std")]
195            Message::RawIq { data } => write!(f, "RawIq {{ data: {:02x?} }}", data)
196        }
197    }
198}
199
200#[cfg_attr(feature = "std", derive(Debug, PartialEq))]
201pub enum ParseMessageError {
202    MissingSeparator,
203    InvalidMessage,
204    InvalidHex(base16::DecodeError),
205    InvalidHexConfigNetwork,
206    InvalidPayloadLength,
207    PayloadTooLong,
208    MissingConfigNetwork,
209}
210
211impl From<base16::DecodeError> for ParseMessageError {
212    fn from(e: base16::DecodeError) -> ParseMessageError {
213        ParseMessageError::InvalidHex(e)
214    }
215}
216
217#[cfg(feature = "std")]
218impl FromStr for Message {
219    type Err = ParseMessageError;
220
221    fn from_str(s: &str) -> Result<Self, ParseMessageError> {
222        if !s.contains('@') {
223            return Err(ParseMessageError::MissingSeparator);
224        }
225
226        let mut iter = s.split(|c| c == '@');
227        let cmd_type = iter.next().unwrap();
228        let val = iter.next().unwrap();
229        match cmd_type {
230            "send" => {
231                let mut data = Vec::<u8, { crate::MAX_LORA_PAYLOAD_LENGTH }>::new();
232                let clean_val = match val.starts_with("0x") || val.starts_with("0X") {
233                    true => &val[2..],
234                    false => &val,
235                };
236                if clean_val.len() / 2 > crate::MAX_LORA_PAYLOAD_LENGTH {
237                    return Err(ParseMessageError::PayloadTooLong);
238                }
239                data.resize_default(clean_val.len() / 2)
240                    .map_err(|_| ParseMessageError::InvalidPayloadLength)?;
241                if base16::decode_slice(clean_val, &mut data).is_err() {
242                    return Err(ParseMessageError::InvalidPayloadLength);
243                }
244
245                Ok(Message::SendData { data })
246            }
247            "status" => Ok(Message::ReportRequest),
248            "config" => {
249                if !val.contains('|') {
250                    return Err(ParseMessageError::MissingSeparator);
251                }
252                let mut iter = val.split(|c| c == '|');
253                let region = iter.next().unwrap();
254                let region = u8::from_str(region).unwrap();
255                let spreading_factor = iter.next().unwrap();
256                let spreading_factor = u8::from_str(spreading_factor).unwrap();
257                if spreading_factor < 7 || spreading_factor > 12 {
258                    return Err(ParseMessageError::InvalidMessage);
259                }
260                let network = iter.next().ok_or(ParseMessageError::MissingConfigNetwork)?;
261                let network = u16::from_str_radix(network, 16)
262                    .map_err(|_| ParseMessageError::InvalidHexConfigNetwork)?;
263                Ok(Message::Configure {
264                    region,
265                    spreading_factor,
266                    network,
267                })
268            }
269            "ts" => Ok(Message::SetTimestamp {
270                timestamp: val.parse().unwrap(),
271            }),
272            "get_rawiq" => Ok(Message::GetRawIq),
273            "uf" => Ok(Message::UpgradeFirmwareRequest),
274            _ => Err(ParseMessageError::InvalidMessage),
275        }
276    }
277}
278
279impl TryFrom<&[u8]> for Message {
280    type Error = Error;
281
282    fn try_from(buf: &[u8]) -> Result<Self, Self::Error> {
283        match buf[0] {
284            0xc0 => Ok(Message::SendData {
285                data: Vec::<u8, 255>::from_slice(&buf[1..])
286                    .map_err(|_| Error::BufferLengthNotSufficient)?,
287            }),
288            0xc1 => Ok(Message::ReceiveData {
289                data: Vec::<u8, 255>::from_slice(&buf[1..])
290                    .map_err(|_| Error::BufferLengthNotSufficient)?,
291            }),
292            0xc2 => Ok(Message::Configure {
293                region: buf[1],
294                spreading_factor: buf[2],
295                network: u16::from_be_bytes(
296                    buf[3..5]
297                        .try_into()
298                        .map_err(|_| Self::Error::CannotParseConfigNetwork)?,
299                ),
300            }),
301            0xc3 => Ok(Message::ReportRequest),
302            0xc4 => Ok(Message::Report {
303                sn: u32::from_be_bytes(buf[1..5].try_into().map_err(|_| Error::MalformedMessage)?),
304                version_data: Vec::<u8, 9>::from_slice(&buf[5..14])
305                    .map_err(|_| Error::MalformedMessage)?,
306
307                region: buf[14],
308                spreading_factor: buf[15],
309                receive_queue_size: buf[16],
310                transmit_queue_size: buf[17],
311                network: u16::from_be_bytes(
312                    buf[18..20]
313                        .try_into()
314                        .map_err(|_| Error::MalformedMessage)?,
315                ),
316            }),
317            0xc5 => Ok(Message::Status {
318                code: buf[1].try_into().map_err(|_| Error::MalformedMessage)?,
319            }),
320            0xc6 => Ok(Message::UpgradeFirmwareRequest),
321            0xc7 => Ok(Message::SetTimestamp {
322                timestamp: u64::from_be_bytes(
323                    buf[1..9].try_into().map_err(|_| Error::MalformedMessage)?,
324                ),
325            }),
326            0xc8 => Ok(Message::GetRawIq),
327            #[cfg(feature = "std")]
328            0xc9 => Ok(Message::RawIq {
329                data: Vec::<u8, RAWIQ_DATA_LENGTH>::from_slice(&buf[1..])
330                    .map_err(|_| Error::BufferLengthNotSufficient)?,
331            }),
332            _ => Err(Error::MalformedMessage),
333        }
334    }
335}
336
337#[allow(clippy::len_without_is_empty)]
338impl Message {
339    pub fn try_from_cobs(buf: &mut [u8]) -> Result<Message, Error> {
340        if buf.is_empty() {
341            return Err(Error::MalformedMessage);
342        };
343
344        let decoded_len = match cobs::decode_in_place_with_sentinel(buf, COBS_SENTINEL) {
345            Ok(len) => len,
346            Err(_) => return Err(Error::MalformedMessage),
347        };
348
349        Message::try_from(&buf[0..decoded_len])
350    }
351
352    pub fn len(&self) -> usize {
353        let variable_part_length = match self {
354            Message::SendData { data } => data.len(),
355            Message::ReceiveData { data } => data.len(),
356            Message::Configure { .. } => 4,
357            Message::ReportRequest => 0,
358            Message::Report { .. } => 19,
359            Message::Status { .. } => 1,
360            Message::UpgradeFirmwareRequest => 0,
361            Message::SetTimestamp { .. } => 8, // 1x u64 timestamp
362            Message::GetRawIq => 0,
363            #[cfg(feature = "std")]
364            Message::RawIq { data } => data.len(),
365        };
366
367        1 + variable_part_length
368    }
369
370    pub fn as_bytes(&self) -> Result<Vec<u8, MAX_MESSAGE_LENGTH>, Error> {
371        let mut res = Vec::new();
372        match self {
373            Message::SendData { data } => {
374                res.push(0xc0)
375                    .map_err(|_| Error::BufferLengthNotSufficient)?;
376                res.extend_from_slice(&data)
377                    .map_err(|_| Error::BufferLengthNotSufficient)?;
378            }
379            Message::ReceiveData { data } => {
380                res.push(0xc1)
381                    .map_err(|_| Error::BufferLengthNotSufficient)?;
382                res.extend_from_slice(&data)
383                    .map_err(|_| Error::BufferLengthNotSufficient)?;
384            }
385            Message::Configure {
386                region,
387                spreading_factor,
388                network,
389            } => {
390                res.extend_from_slice(&[0xc2, *region, *spreading_factor])
391                    .map_err(|_| Error::BufferLengthNotSufficient)?;
392                res.extend_from_slice(&network.to_be_bytes())
393                    .map_err(|_| Error::BufferLengthNotSufficient)?;
394            }
395            Message::ReportRequest => res
396                .push(0xc3)
397                .map_err(|_| Error::BufferLengthNotSufficient)?,
398            // TODO move MessageType to wireless-protocol
399            Message::Report {
400                sn,
401                version_data,
402                region,
403                spreading_factor,
404                receive_queue_size,
405                transmit_queue_size,
406                network,
407            } => {
408                res.push(0xc4)
409                    .map_err(|_| Error::BufferLengthNotSufficient)?;
410                res.extend_from_slice(&u32::to_be_bytes(*sn))
411                    .map_err(|_| Error::BufferLengthNotSufficient)?;
412                res.extend_from_slice(&version_data)
413                    .map_err(|_| Error::BufferLengthNotSufficient)?;
414                res.extend_from_slice(&[
415                    *region,
416                    *spreading_factor,
417                    *receive_queue_size,
418                    *transmit_queue_size,
419                ])
420                .map_err(|_| Error::BufferLengthNotSufficient)?;
421                res.extend_from_slice(&network.to_be_bytes())
422                    .map_err(|_| Error::BufferLengthNotSufficient)?;
423            }
424            Message::Status { code } => {
425                res.extend_from_slice(&[0xc5, code.clone() as u8])
426                    .map_err(|_| Error::BufferLengthNotSufficient)?;
427            }
428            Message::UpgradeFirmwareRequest => res
429                .push(0xc6)
430                .map_err(|_| Error::BufferLengthNotSufficient)?,
431            Message::SetTimestamp { timestamp } => {
432                res.push(0xc7)
433                    .map_err(|_| Error::BufferLengthNotSufficient)?;
434                res.extend_from_slice(&u64::to_be_bytes(*timestamp))
435                    .map_err(|_| Error::BufferLengthNotSufficient)?
436            }
437            Message::GetRawIq => res
438                .push(0xc8)
439                .map_err(|_| Error::BufferLengthNotSufficient)?,
440            #[cfg(feature = "std")]
441            Message::RawIq { data } => {
442                res.push(0xc9)
443                    .map_err(|_| Error::BufferLengthNotSufficient)?;
444                res.extend_from_slice(&data)
445                    .map_err(|_| Error::BufferLengthNotSufficient)?;
446            }
447        };
448        Ok(res)
449    }
450
451    pub fn encode(&self) -> Result<HostMessageVec, Error> {
452        let mut result = HostMessageVec::new(); // Maximum message length is 256 + cobs overhead
453        let mut encoded_len = cobs::max_encoding_length(self.len() + 1);
454        result
455            .resize_default(encoded_len)
456            .map_err(|_| Error::BufferLengthNotSufficient)?;
457        let mut enc = cobs::CobsEncoder::new(&mut result);
458        enc.push(self.as_bytes()?.as_slice())
459            .map_err(|_| Error::CobsEncodeError)?;
460
461        encoded_len = enc.finalize().map_err(|_| Error::CobsEncodeError)?;
462        result
463            .push(COBS_SENTINEL)
464            .map_err(|_| Error::BufferLengthNotSufficient)?;
465        result.truncate(encoded_len + 1_usize);
466        Ok(result)
467    }
468
469    pub fn encode_to_slice<'a>(&self, buf: &'a mut [u8]) -> Result<usize, Error> {
470        let mut enc = cobs::CobsEncoder::new(buf);
471        enc.push(self.as_bytes()?.as_slice())
472            .map_err(|_| Error::CobsEncodeError)?;
473
474        let encoded_len = enc.finalize().map_err(|_| Error::CobsEncodeError)?;
475        buf[encoded_len] = COBS_SENTINEL;
476        Ok(encoded_len + 1)
477    }
478
479    pub fn into_encoded_bytes(self) -> Result<HostMessageVec, Error> {
480        self.encode()
481    }
482
483    /// Splits COBS encoded self to frames for sending.
484    /// Frames can be send as is over the wire, it itself is a valid host protocol packet
485    pub fn as_frames<C: codec::WireCodec>(&self) -> Result<C::Frames, Error> {
486        let mut result = self.encode()?;
487        let frames = C::get_frames(&mut result[..]).map_err(|e| Error::CodecError(e))?;
488        Ok(frames)
489    }
490}
491
492pub struct MessageReader<const BUFL: usize, const QL: usize> {
493    buf: Vec<u8, BUFL>,
494}
495
496impl<const BUFL: usize, const QL: usize> MessageReader<BUFL, QL> {
497    pub fn new() -> Self {
498        Self {
499            buf: Vec::<u8, BUFL>::new(),
500        }
501    }
502
503    pub fn process_bytes<C: codec::WireCodec>(
504        &mut self,
505        bytes: &[u8],
506    ) -> Result<Vec<Message, QL>, Error> {
507        let (bytes, decoded_len) = C::decode_frame(bytes)?;
508        if self.buf.len() + decoded_len > BUFL {
509            return Err(Error::BufferFull);
510        }
511        self.buf.extend(bytes);
512
513        let mut output = Vec::<Message, QL>::new();
514        let mut cobs_index: usize = 0;
515
516        if !&self.buf.contains(&COBS_SENTINEL) {
517            return Ok(output);
518        }
519        loop {
520            if self.buf[cobs_index] == COBS_SENTINEL {
521                match Message::try_from_cobs(&mut self.buf[0..cobs_index]) {
522                    Ok(command) => {
523                        self.buf = Vec::from_slice(&self.buf[cobs_index + 1..])
524                            .map_err(|_| Error::BufferLengthNotSufficient)?; // +1 do not include the COBS_SENTINEL
525                        cobs_index = 0;
526                        if output.len() < QL {
527                            output
528                                .push(command)
529                                .map_err(|_| Error::CannotAppendCommand)?;
530                        } else {
531                            return Err(Error::MessageQueueFull);
532                        }
533                        if self.buf.len() == 0 {
534                            break;
535                        } else {
536                            continue;
537                        }
538                    }
539                    Err(_) => return Err(Error::MalformedMessage),
540                }
541            }
542
543            if cobs_index + 1 == self.buf.len() {
544                break;
545            }
546
547            cobs_index += 1;
548        }
549        Ok(output)
550    }
551
552    pub fn ltrim(&mut self, length: usize) -> Result<(), Error> {
553        if self.buf.len() < length {
554            return Err(Error::BufferLengthNotSufficient);
555        }
556
557        self.buf = match Vec::from_slice(&self.buf[length..]) {
558            Ok(b) => b,
559            Err(_) => return Err(Error::BufferLengthNotSufficient),
560        };
561        Ok(())
562    }
563
564    pub fn reset(&mut self) {
565        self.buf.clear();
566    }
567
568    pub fn is_empty(&self) -> bool {
569        self.buf.is_empty()
570    }
571}
572
573impl<const BUFL: usize, const QL: usize> Default for MessageReader<BUFL, QL> {
574    fn default() -> Self {
575        Self::new()
576    }
577}
578
579#[cfg(test)]
580mod tests {
581    use super::*;
582    use rand::{thread_rng, Rng};
583
584    #[test]
585    fn test_msg_len() {
586        assert_eq!(
587            20,
588            Message::Report {
589                region: 0x01,
590                spreading_factor: 7,
591                sn: 12345678u32,
592                version_data: Vec::<u8, 9>::from_slice(&[
593                    0x01, 0x00, 0x01, 0x00, 0x04, 0x40, 0x6e, 0xd3, 0x01,
594                ])
595                .unwrap(), // hw revision, firmware version 0.1.0, commit 4406ed3, dirty
596                receive_queue_size: 1,
597                transmit_queue_size: 3,
598                network: u16::from_be_bytes([0xaa, 0xcc])
599            }
600            .len()
601        );
602        assert_eq!(1, Message::ReportRequest.len());
603        assert_eq!(
604            5,
605            Message::Configure {
606                region: 0x1,
607                spreading_factor: 7,
608                network: u16::from_be_bytes([0xaa, 0xcc])
609            }
610            .len()
611        );
612        assert_eq!(
613            3,
614            Message::SendData {
615                data: Vec::<u8, 255>::from_slice(&[0xff, 0xee]).unwrap()
616            }
617            .len()
618        );
619        assert_eq!(
620            5,
621            Message::ReceiveData {
622                data: Vec::<u8, 255>::from_slice(&[0xde, 0xad, 0xbe, 0xef]).unwrap()
623            }
624            .len()
625        );
626    }
627
628    #[test]
629    fn test_process_with_no_bytes_is_empty() {
630        let mut cr = MessageReader::<MAX_MESSAGE_LENGTH, DEFAULT_MAX_MESSAGE_QUEUE_LENGTH>::new();
631        assert_eq!(
632            cr.process_bytes::<codec::UsbCodec>(&[][..]).unwrap().len(),
633            0
634        );
635    }
636
637    #[test]
638    fn test_process_with_no_full_message_is_empty() {
639        let mut cr = MessageReader::<MAX_MESSAGE_LENGTH, DEFAULT_MAX_MESSAGE_QUEUE_LENGTH>::new();
640        assert_eq!(
641            cr.process_bytes::<codec::UsbCodec>(&[0x01, 0x02][..])
642                .unwrap()
643                .len(),
644            0
645        );
646    }
647
648    #[test]
649    fn test_single_message_decoding() {
650        let encoded = &[0x06, 0xc2, 0xff, 0x07, 0xaa, 0xcc, 0x00];
651        let mut cr = MessageReader::<MAX_MESSAGE_LENGTH, DEFAULT_MAX_MESSAGE_QUEUE_LENGTH>::new();
652        let messages = cr.process_bytes::<codec::UsbCodec>(&encoded[..]).unwrap();
653
654        let expected_msg_0 = Message::Configure {
655            region: 255u8,
656            spreading_factor: 7,
657            network: u16::from_be_bytes([0xaa, 0xcc]),
658        };
659        assert_eq!(messages.len(), 1);
660        assert_eq!(messages[0], expected_msg_0);
661    }
662
663    #[test]
664    fn test_multiple() {
665        let mut encoded_buffer = [128; 32];
666        let mut start = 0;
667        for msg in vec![vec![0xc0, 0xff, 0xee], vec![0xc1, 0xde, 0xad, 0xbe, 0xef]] {
668            println!("start index is = {}", start);
669            let written = cobs::encode(&msg, &mut encoded_buffer[start..]);
670            println!("encoded_buffer -> {:02x?}", encoded_buffer);
671            encoded_buffer[start + written] = 0x00;
672            println!(
673                "start = {}, written = {}\nencoded_buffer -> {:02x?}",
674                start,
675                written + 1,
676                encoded_buffer
677            );
678            start = start + written + 1;
679        }
680
681        let mut cr = MessageReader::<MAX_MESSAGE_LENGTH, 2>::new();
682        let messages = cr
683            .process_bytes::<codec::UsbCodec>(&encoded_buffer[..])
684            .unwrap();
685        assert_eq!(messages.len(), 2);
686        assert_eq!(
687            messages[0],
688            Message::SendData {
689                data: Vec::<u8, 255>::from_slice(&[0xff, 0xee]).unwrap()
690            }
691        );
692        assert_eq!(
693            messages[1],
694            Message::ReceiveData {
695                data: Vec::<u8, 255>::from_slice(&[0xde, 0xad, 0xbe, 0xef]).unwrap()
696            }
697        );
698    }
699
700    // TODO test the rest of the message types
701    #[test]
702    fn test_more_than_queue_capacity() {
703        let mut encoded_buffer = [128; 32];
704        let mut start = 0;
705        for msg in vec![
706            vec![0xc0, 0xff, 0xee],
707            vec![0xc0, 0xff, 0xee],
708            vec![0xc0, 0xff, 0xee],
709            vec![0xc0, 0xff, 0xee],
710            vec![0xc0, 0xff, 0xee],
711        ] {
712            println!("start index is = {}", start);
713            let written = cobs::encode(&msg, &mut encoded_buffer[start..]);
714            println!("encoded_buffer -> {:02x?}", encoded_buffer);
715            encoded_buffer[start + written] = 0x00;
716            println!(
717                "start = {}, written = {}\nencoded_buffer -> {:02x?}",
718                start,
719                written + 1,
720                encoded_buffer
721            );
722            start = start + written + 1;
723        }
724        let mut cr = MessageReader::<MAX_MESSAGE_LENGTH, DEFAULT_MAX_MESSAGE_QUEUE_LENGTH>::new();
725        let err = cr.process_bytes::<codec::UsbCodec>(&encoded_buffer[..]);
726        assert_eq!(err, Err(Error::MessageQueueFull));
727    }
728
729    #[test]
730    fn test_single_message_encoding_as_cobs_encoded_usb_frames() {
731        let expected = &[0x06, 0xc2, 0xff, 0x07, 0xaa, 0xcc, 0x00];
732        let msg = Message::Configure {
733            region: 255u8,
734            spreading_factor: 7,
735            network: u16::from_be_bytes([0xaa, 0xcc]),
736        };
737        let frames = msg.as_frames::<codec::UsbCodec>().unwrap();
738
739        assert_eq!(frames.len(), 1);
740        let result = &frames[0];
741        println!("encoded = {:02x?}", &result);
742        assert_eq!(result, expected);
743    }
744
745    #[test]
746    fn test_max_len_data_message_encoding() {
747        let mut arr = [0u8; crate::MAX_LORA_PAYLOAD_LENGTH];
748        thread_rng().try_fill(&mut arr[..]).unwrap();
749
750        let msg = Message::SendData {
751            data: Vec::<u8, { crate::MAX_LORA_PAYLOAD_LENGTH }>::from_slice(&arr).unwrap(),
752        };
753
754        // msg get encoded to more than MaxSerialFrameLength so we should get 2 frames
755        let frames = msg.as_frames::<codec::UsbCodec>().unwrap();
756        assert_eq!(frames.len(), 2);
757
758        // lets check the the second (last) frame has COBS_SENTINEL at the end
759        let last_frame = &frames.last().unwrap();
760        assert_eq!(last_frame.last().unwrap(), &COBS_SENTINEL);
761    }
762
763    #[test]
764    fn test_ltrim_ok() {
765        let mut cr = MessageReader::<MAX_MESSAGE_LENGTH, DEFAULT_MAX_MESSAGE_QUEUE_LENGTH>::new();
766        let buf = b"%DISCONNECT%";
767        cr.process_bytes::<codec::UsbCodec>(buf.as_ref()).unwrap();
768        let res = cr.ltrim(buf.len());
769        assert_eq!(Ok(()), res);
770    }
771
772    #[test]
773    fn test_ltrim_err() {
774        let mut cr = MessageReader::<MAX_MESSAGE_LENGTH, DEFAULT_MAX_MESSAGE_QUEUE_LENGTH>::new();
775        let buf = b"%DISCONNECT%";
776        cr.process_bytes::<codec::UsbCodec>(buf.as_ref()).unwrap();
777        let err = cr.ltrim(buf.len() + 1);
778        assert_eq!(err, Err(Error::BufferLengthNotSufficient));
779    }
780
781    #[test]
782    fn test_single_message_encoding_as_cobs_encoded_frames_for_ble() {
783        let expected = &[0x06, 0xc2, 0xff, 0x0c, 0xaa, 0xcc, 0x00];
784        let msg = Message::Configure {
785            region: 255u8,
786            spreading_factor: 12,
787            network: u16::from_be_bytes([0xaa, 0xcc]),
788        };
789        let hex_frames = msg.as_frames::<codec::Rn4870Codec>().unwrap();
790
791        assert_eq!(hex_frames.len(), 1);
792        let hex_frame = &hex_frames[0];
793        let mut decoded = Vec::<u8, 7>::new();
794        decoded.resize_default(expected.len()).unwrap();
795        base16::decode_slice(&hex_frame.clone()[1..hex_frame.len() - 1], &mut decoded).unwrap();
796        assert_eq!(decoded, expected);
797    }
798
799    #[test]
800    fn test_message_reader_process_bytes_hex() {
801        let msg = Message::Configure {
802            region: 255u8,
803            spreading_factor: 7,
804            network: u16::from_be_bytes([0xaa, 0xcc]),
805        };
806        let hex_frames = msg.as_frames::<codec::Rn4870Codec>().unwrap();
807
808        assert_eq!(hex_frames.len(), 1);
809        let hex_frame = hex_frames[0].clone();
810        let mut cr = MessageReader::<MAX_MESSAGE_LENGTH, DEFAULT_MAX_MESSAGE_QUEUE_LENGTH>::new();
811        let messages = cr
812            .process_bytes::<codec::Rn4870Codec>(&hex_frame[1..hex_frame.len() - 1])
813            .unwrap();
814        assert_eq!(messages.len(), 1);
815        assert_eq!(messages[0], msg);
816    }
817
818    #[test]
819    fn test_max_message_length_as_cobs_encoded_frames_for_ble() {
820        let mut arr = [0u8; crate::MAX_LORA_PAYLOAD_LENGTH];
821        thread_rng().try_fill(&mut arr[..]).unwrap();
822
823        let msg = Message::SendData {
824            data: Vec::<u8, { crate::MAX_LORA_PAYLOAD_LENGTH }>::from_slice(&arr).unwrap(),
825        };
826
827        // msg get encoded to more than MaxSerialFrameLength so we should get 5 frames
828        let frames = msg.as_frames::<codec::Rn4870Codec>().unwrap();
829        assert_eq!(frames.len(), 5);
830    }
831
832    #[test]
833    fn test_status_code_encoding() {
834        let msg = Message::Status {
835            code: StatusCode::ErrBusyLoraTransmitting,
836        };
837        let encoded = msg.encode().unwrap();
838        let mut mr = MessageReader::<MAX_MESSAGE_LENGTH, DEFAULT_MAX_MESSAGE_QUEUE_LENGTH>::new();
839        let messages = mr.process_bytes::<codec::UsbCodec>(&encoded[..]).unwrap();
840        assert_eq!(messages.len(), 1);
841        assert_eq!(messages[0], msg);
842    }
843
844    #[test]
845    fn test_encode_to_slice_status() {
846        let mut result = [0u8; 20];
847        let msg = Message::Status {
848            code: StatusCode::ErrBusyLoraTransmitting,
849        };
850        let result_len = msg.encode_to_slice(&mut result[..]).unwrap();
851        assert_eq!(result[0..result_len], msg.encode().unwrap()[..]);
852    }
853
854    #[test]
855    fn test_encode_to_slice_receive_data() {
856        let mut result = [0u8; 68];
857        let msg = Message::ReceiveData {
858            data: Vec::<u8, 255>::from_slice([0xab].repeat(64).as_slice()).unwrap(),
859        };
860        let result_len = msg.encode_to_slice(&mut result[..]).unwrap();
861        assert_eq!(result[0..result_len], msg.encode().unwrap()[..]);
862    }
863
864    #[test]
865    fn test_encode_to_slice_report() {
866        let mut result = [0u8; 68];
867        let msg = Message::Report {
868            sn: 0xa1a2a3a4,
869            version_data: Vec::<u8, 9>::from_slice(&[
870                0x01, 0x00, 0x01, 0x00, 0x04, 0x40, 0x6e, 0xd3, 0x01,
871            ])
872            .unwrap(), // hw revision, firmware version 0.1.0, commit 4406ed3, dirty
873            region: 13,
874            spreading_factor: 7,
875            receive_queue_size: 17, // TODO this should track messages not read by BLE connected host yet
876            transmit_queue_size: 25,
877            network: u16::from_be_bytes([0xaa, 0xcc]),
878        };
879        let result_len = msg.encode_to_slice(&mut result[..]).unwrap();
880        println!("{:02x?}", &result[0..result_len]);
881        assert_eq!(result[0..result_len], msg.encode().unwrap()[..]);
882    }
883
884    #[test]
885    fn test_message_parse_status() {
886        let msg = "status@".parse::<Message>().unwrap();
887        assert_eq!(msg, Message::ReportRequest);
888    }
889
890    #[test]
891    fn test_message_parse_send_data() {
892        let msg = "send@0xAABB".parse::<Message>().unwrap();
893        assert_eq!(
894            msg,
895            Message::SendData {
896                data: Vec::<u8, { crate::MAX_LORA_PAYLOAD_LENGTH }>::from_slice(&[0xaa, 0xbb])
897                    .unwrap()
898            }
899        );
900
901        let msg = "send@ccdd".parse::<Message>().unwrap();
902        assert_eq!(
903            msg,
904            Message::SendData {
905                data: Vec::<u8, { crate::MAX_LORA_PAYLOAD_LENGTH }>::from_slice(&[0xcc, 0xdd])
906                    .unwrap()
907            }
908        );
909    }
910
911    #[test]
912    fn test_message_parse_config() {
913        let msg = "config@1|7|aacc".parse::<Message>().unwrap();
914        assert_eq!(
915            msg,
916            Message::Configure {
917                region: 1,
918                spreading_factor: 7,
919                network: u16::from_be_bytes([0xaa, 0xcc])
920            }
921        );
922    }
923
924    #[test]
925    fn test_message_parse_config_invalid_sf() {
926        let err = "config@1|6|aacc".parse::<Message>();
927        assert_eq!(err, Err(ParseMessageError::InvalidMessage));
928
929        let err = "config@1|13|ccaa".parse::<Message>();
930        assert_eq!(err, Err(ParseMessageError::InvalidMessage));
931    }
932
933    #[test]
934    #[should_panic(expected = "MissingConfigNetwork")]
935    fn test_message_parse_config_missing_network() {
936        "config@1|12".parse::<Message>().unwrap();
937    }
938
939    #[test]
940    fn test_message_parse_ts() {
941        let msg = "ts@1629896485".parse::<Message>().unwrap();
942        assert_eq!(
943            msg,
944            Message::SetTimestamp {
945                timestamp: 1629896485u64
946            }
947        );
948    }
949
950    #[test]
951    fn test_calculate_cobs_overhead_for_255() {
952        let max_message_length = calculate_cobs_overhead(255);
953        assert_eq!(max_message_length, 260);
954    }
955
956    #[test]
957    fn test_calculate_cobs_overhead_for_2048() {
958        let max_message_length = calculate_cobs_overhead(2048);
959        assert_eq!(max_message_length, 2060);
960    }
961
962    #[test]
963    fn test_calculate_cobs_overhead_for_4096() {
964        let max_message_length = calculate_cobs_overhead(4096);
965        assert_eq!(max_message_length, 4116);
966    }
967}