electricui_embedded/
decoder.rs

1use crate::sealed;
2use crate::wire::{packet, Packet};
3use err_derive::Error;
4
5#[derive(Debug, Copy, Clone, Eq, PartialEq, Error)]
6pub enum Error {
7    #[error(display = "Not enough bytes in the decoder buffer to store the frame")]
8    InsufficientBufferSize,
9
10    #[error(display = "Encountered a packet error. {}", _0)]
11    PacketError(#[error(source)] packet::Error),
12}
13
14#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
15enum State {
16    FrameOffset,
17    HeaderB0,
18    HeaderB1,
19    HeaderB2,
20    MsgId,
21    OffsetB0,
22    OffsetB1,
23    Payload,
24    CrcB0,
25    CrcB1,
26}
27
28#[derive(Debug)]
29pub struct Decoder<'buf, const N: usize> {
30    state: State,
31
32    frame_offset: u8,
33    id_bytes_read: u8,
34    data_bytes_read: u16,
35    bytes_read: usize,
36    valid_pkt_count: usize,
37    invalid_pkt_count: usize,
38
39    data_len: u16,
40    offset: bool,
41    id_len: u8,
42
43    packet_storage: &'buf mut [u8; N],
44}
45
46impl<'buf, const N: usize> Decoder<'buf, N> {
47    pub fn new(packet_storage: &'buf mut [u8; N]) -> Self {
48        sealed::greater_than_eq::<N, { Packet::<&[u8]>::BASE_PACKET_SIZE }>();
49        Self {
50            state: State::FrameOffset,
51            frame_offset: 0,
52            id_bytes_read: 0,
53            data_bytes_read: 0,
54            bytes_read: 0,
55            valid_pkt_count: 0,
56            invalid_pkt_count: 0,
57            data_len: 0,
58            offset: false,
59            id_len: 0,
60            packet_storage,
61        }
62    }
63
64    #[inline]
65    pub fn reset(&mut self) {
66        self.state = State::FrameOffset;
67        self.frame_offset = 0;
68        self.bytes_read = 0;
69    }
70
71    pub fn count(&self) -> usize {
72        self.valid_pkt_count
73    }
74
75    pub fn invalid_count(&self) -> usize {
76        self.invalid_pkt_count
77    }
78
79    pub fn decode(&mut self, mut byte: u8) -> Result<Option<Packet<&[u8]>>, Error> {
80        // COBS framing
81        if byte == 0x00 {
82            self.reset();
83            return Ok(None);
84        } else if self.frame_offset > 1 {
85            // One byte closer to the next offset
86            self.frame_offset -= 1;
87        } else {
88            // Offset has expired, this inbound byte should be the next data framing byte
89            self.frame_offset = byte;
90            byte = 0x00;
91        }
92
93        match self.state {
94            State::FrameOffset => {
95                // First byte is the first offset
96                self.state = State::HeaderB0;
97            }
98            State::HeaderB0 => {
99                self.feed(byte)?;
100                self.data_len = byte as _;
101                self.state = State::HeaderB1;
102            }
103            State::HeaderB1 => {
104                self.feed(byte)?;
105                self.data_len |= ((byte as u16) << 8) & 0x0300;
106                self.offset = ((byte >> 7) & 0x01) != 0;
107                self.state = State::HeaderB2;
108            }
109            State::HeaderB2 => {
110                self.feed(byte)?;
111                self.id_len = byte & 0x0F;
112                self.id_bytes_read = 0;
113                self.state = State::MsgId;
114            }
115            State::MsgId => {
116                self.feed(byte)?;
117                self.id_bytes_read = self.id_bytes_read.saturating_add(1);
118                if self.id_bytes_read >= self.id_len {
119                    if self.offset {
120                        self.state = State::OffsetB0
121                    } else if self.data_len > 0 {
122                        self.data_bytes_read = 0;
123                        self.state = State::Payload;
124                    } else {
125                        self.state = State::CrcB0;
126                    }
127                }
128            }
129            State::OffsetB0 => {
130                // TODO - Add support for split/offset packets
131                self.feed(byte)?;
132                self.state = State::OffsetB1;
133            }
134            State::OffsetB1 => {
135                // TODO - Add support for split/offset packets
136                self.feed(byte)?;
137                self.state = State::Payload;
138            }
139            State::Payload => {
140                self.feed(byte)?;
141                self.data_bytes_read = self.data_bytes_read.saturating_add(1);
142                if self.data_bytes_read >= self.data_len {
143                    self.state = State::CrcB0;
144                }
145            }
146            State::CrcB0 => {
147                self.feed(byte)?;
148                self.state = State::CrcB1;
149            }
150            State::CrcB1 => {
151                self.feed(byte)?;
152                let bytes_read = self.bytes_read;
153                self.reset();
154                match Packet::new(&self.packet_storage[..bytes_read]) {
155                    Ok(p) => {
156                        self.valid_pkt_count = self.valid_pkt_count.saturating_add(1);
157                        return Ok(p.into());
158                    }
159                    Err(e) => {
160                        self.invalid_pkt_count = self.invalid_pkt_count.saturating_add(1);
161                        return Err(e.into());
162                    }
163                }
164            }
165        }
166
167        Ok(None)
168    }
169
170    #[inline]
171    fn feed(&mut self, byte: u8) -> Result<(), Error> {
172        if self.bytes_read >= self.packet_storage.len() {
173            Err(Error::InsufficientBufferSize)
174        } else {
175            self.packet_storage[self.bytes_read] = byte;
176            self.bytes_read = self.bytes_read.saturating_add(1);
177            Ok(())
178        }
179    }
180}
181
182#[cfg(test)]
183mod tests {
184    use super::*;
185    use pretty_assertions::assert_eq;
186
187    // TODO - happy/sad path tests
188
189    static MSG_F32: [u8; 12 + 2] = [
190        0x00, 0x0D, // framing
191        0x04, 0x2c, 0x03, // header
192        0x61, 0x62, 0x63, // msgid
193        0x14, 0xAE, 0x29, 0x42, // payload
194        0x8B, 0x1D, // crc
195    ];
196
197    #[test]
198    fn basic_decoding() {
199        let mut buffer = [0_u8; 512];
200        let mut dec = Decoder::new(&mut buffer);
201
202        for _ in 0..4 {
203            for (idx, byte) in MSG_F32.iter().enumerate() {
204                let maybe_frame = dec.decode(*byte).unwrap();
205                if idx < (MSG_F32.len() - 1) {
206                    assert_eq!(maybe_frame.is_some(), false);
207                } else {
208                    assert_eq!(maybe_frame.is_some(), true);
209                }
210            }
211
212            // Mix in some junk in between
213            assert!(dec.decode(1).unwrap().is_none());
214            assert!(dec.decode(0).unwrap().is_none());
215            assert!(dec.decode(2).unwrap().is_none());
216        }
217
218        assert_eq!(dec.count(), 4);
219        assert_eq!(dec.invalid_count(), 0);
220    }
221}