1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#![no_std]

mod parser;

use core::fmt::Debug;
use embedded_hal::{self, nb, serial};

#[derive(Debug, PartialEq, Eq, Clone, Copy, derive_more::From)]
pub enum Error<SerialError> {
    Serial(SerialError),
    #[from]
    Parse(ParseError),
    Overflow,
}

#[cfg(feature = "defmt")]
impl<SerialError: Debug> defmt::Format for Error<SerialError> {
    fn format(&self, fmt: defmt::Formatter) {
        match self {
            Self::Serial(e) => {
                let e = defmt::Debug2Format(&e);
                defmt::write!(fmt, "Communication with serial failed: {}", e)
            }
            Self::Parse(e) => defmt::write!(fmt, "Failed to parse response: {}", &e),
            Self::Overflow => defmt::write!(fmt, "Overflow"),
        }
    }
}

pub struct Lora<Serial> {
    serial: Serial,
}

impl<Serial> Lora<Serial>
where
    Serial: serial::nb::Write<u8> + serial::nb::Read<u8>,
{
    pub fn new(serial: Serial) -> Self {
        Self { serial }
    }

    pub fn into_serial(self) -> Serial {
        self.serial
    }

    /// Drains serial until it hits `\r\n`
    fn drain(&mut self, mut last_byte: Option<u8>) -> Result<(), Error<Serial::Error>> {
        loop {
            let b = nb::block!(self.serial.read()).map_err(Error::Serial)?;
            if last_byte == Some(b'\r') && b == b'\n' {
                break Ok(());
            }
            last_byte = Some(b);
        }
    }

    pub fn send(&mut self, cmd: &[u8]) -> Result<(), Error<Serial::Error>> {
        for &b in cmd {
            nb::block!(self.serial.write(b)).map_err(Error::Serial)?;
        }

        Ok(())
    }

    pub fn receive(&mut self, buffer: &mut [u8]) -> Result<usize, Error<Serial::Error>> {
        let mut i = 0;
        loop {
            let is_overflow = i == buffer.len();
            if is_overflow {
                // ignore error if communication failed
                let _ = self.drain(buffer.last().cloned());
                break Err(Error::Overflow);
            }

            let b = nb::block!(self.serial.read()).map_err(Error::Serial)?;

            buffer[i] = b;
            i += 1;

            let response_end = buffer[..i].ends_with(b"\r\n");
            if response_end {
                break Ok(i);
            }
        }
    }
}

#[derive(Debug, PartialEq, Eq)]
pub struct Response<'a> {
    pub header: &'a [u8],
    pub content: ResponseContent<'a>,
}

#[derive(Debug, PartialEq, Eq)]
pub enum ResponseContent<'a> {
    Data(&'a [u8]),
    Error(i8),
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum ParseError {
    Incomplete,
    BadCommand,
    BadErrorCode,
    NoDelimiter,
    NoPrefix,
    NoTerminator,
    UnclosedErrorParen,
    Unknown,
}

#[cfg(feature = "defmt")]
impl defmt::Format for ParseError {
    fn format(&self, fmt: defmt::Formatter) {
        match self {
            Self::Incomplete => defmt::write!(fmt, "Incomplete response"),
            Self::BadCommand => defmt::write!(fmt, "Invalid command header"),
            Self::BadErrorCode => defmt::write!(fmt, "Invalid error code"),
            Self::NoDelimiter => defmt::write!(fmt, "Missing the `:` delimiter"),
            Self::NoPrefix => defmt::write!(fmt, "Missing `+` before the header"),
            Self::NoTerminator => defmt::write!(fmt, "Missing message terminator"),
            Self::UnclosedErrorParen => defmt::write!(fmt, "Unclosed error parentheses"),
            Self::Unknown => defmt::write!(fmt, "Unknown"),
        }
    }
}

pub fn parse_response(input: &[u8]) -> Result<Response, ParseError> {
    match parser::response(input) {
        Ok((_i, o)) => Ok(o),
        Err(nom::Err::Error(e) | nom::Err::Failure(e)) => Err(e),
        Err(nom::Err::Incomplete(_)) => Err(ParseError::Incomplete),
    }
}