negicon_protocol/
negicon_message.rs

1use defmt::{bitflags, Format};
2pub use ux::u7;
3
4use crate::{make_u32, util::make_u16};
5use core::ops::Shr;
6#[derive(Clone, Copy, PartialEq, Debug)]
7pub struct NegiconFrame {
8    pub origin: u16,
9    pub destination: u16,
10    pub message_type: NegiconMessageType,
11    reserved: u8,
12    pub message_data: [u8; 8],
13}
14
15#[derive(PartialEq, Clone, Copy, Debug)]
16pub enum NegiconMessageType {
17    Nop = 0,
18    Ping = 1,
19    ModuleEventShort = 2,
20    ModuleEventLong = 3,
21    ModuleEventDouble = 4,
22}
23
24impl NegiconMessageType {
25    fn from_u8(value: u8) -> Result<Self, InvalidMessage> {
26        match value {
27            0 => Ok(NegiconMessageType::Nop),
28            1 => Ok(NegiconMessageType::Ping),
29            2 => Ok(NegiconMessageType::ModuleEventLong),
30            3 => Ok(NegiconMessageType::ModuleEventDouble),
31            _ => Err(InvalidMessage::InvalidMessageType),
32        }
33    }
34}
35
36#[derive(PartialEq, Clone, Copy, Debug)]
37pub enum NegiconModuleType {
38    Invalid = 0,
39    Router,
40    Buttons,
41    SmoothEncoder,
42    DetentEncoder,
43    ClickWheel,
44    DigitalPaddle,
45    AnalogPaddle,
46}
47
48impl NegiconModuleType {
49    fn from_u8(value: u8) -> Self {
50        match value {
51            0 => NegiconModuleType::Router,
52            1 => NegiconModuleType::Buttons,
53            2 => NegiconModuleType::SmoothEncoder,
54            3 => NegiconModuleType::DetentEncoder,
55            4 => NegiconModuleType::ClickWheel,
56            5 => NegiconModuleType::DigitalPaddle,
57            6 => NegiconModuleType::AnalogPaddle,
58            _ => NegiconModuleType::Invalid,
59        }
60    }
61}
62
63#[derive(PartialEq, Clone, Copy, Debug, Format)]
64pub enum InvalidMessage {
65    CrcError,
66    InvalidMessageType,
67}
68
69const CRC: crc::Crc<u16> = crc::Crc::<u16>::new(&crc::CRC_16_IBM_3740);
70
71fn crc(data: &[u8]) -> u16 {
72    CRC.checksum(data)
73}
74
75fn set_crc(data: &mut [u8]) {
76    let crc = crc(&data[2..]);
77    data[1] = crc as u8;
78    data[0] = (crc >> 8) as u8;
79}
80fn verify_crc(data: &[u8]) -> Result<(), InvalidMessage> {
81    let expected = make_u16(data[0], data[1]);
82    let actual = crc(&data[2..]);
83    if expected == actual {
84        Ok(())
85    } else {
86        Err(InvalidMessage::CrcError)
87    }
88}
89
90#[derive(PartialEq, Clone, Copy, Debug)]
91pub struct NegiconPingMessage {
92    pub sequence: u8,
93    pub ttl: u8,
94    pub module_type: NegiconModuleType,
95    pub fw_version: u16,
96}
97
98impl NegiconPingMessage {
99    pub fn serialize(&self) -> [u8; 8] {
100        [
101            self.sequence,
102            self.ttl,
103            self.module_type as u8,
104            self.fw_version.shr(8) as u8,
105            self.fw_version as u8,
106            0u8,
107            0u8,
108            0u8,
109        ]
110    }
111
112    pub fn deserialize(data: &[u8; 8]) -> Result<Self, InvalidMessage> {
113        Ok(NegiconPingMessage {
114            sequence: data[0],
115            ttl: data[1],
116            module_type: NegiconModuleType::from_u8(data[2]),
117            fw_version: make_u16(data[3], data[4]),
118        })
119    }
120}
121
122#[derive(PartialEq, Clone, Copy, Debug)]
123pub struct NegiconModuleEventLongMessage {
124    pub sequence: u8,
125    pub sub_id: u8,
126    pub event_data: [u8; 6],
127}
128
129impl NegiconModuleEventLongMessage {
130    pub fn serialize(&self) -> [u8; 8] {
131        [
132            self.sequence,
133            self.sub_id,
134            self.event_data[0],
135            self.event_data[1],
136            self.event_data[2],
137            self.event_data[3],
138            self.event_data[4],
139            self.event_data[5],
140        ]
141    }
142
143    pub fn deserialize(data: &[u8; 8]) -> Result<Self, InvalidMessage> {
144        Ok(NegiconModuleEventLongMessage {
145            sequence: data[0],
146            sub_id: data[1],
147            event_data: [data[2], data[3], data[4], data[5], data[6], data[7]],
148        })
149    }
150}
151
152#[derive(PartialEq, Clone, Copy, Debug)]
153pub struct NegiconModuleEventShortMessage {
154    pub sequence: u8,
155    pub sub_id: u8,
156    pub value: u16,
157}
158
159impl NegiconModuleEventShortMessage {
160    pub fn new(sequence: u8, sub_id: u8, value: u16) -> Self {
161        Self {
162            sequence,
163            sub_id,
164            value,
165        }
166    }
167
168    pub fn serialize(&self) -> [u8; 4] {
169        [
170            self.sequence,
171            self.sub_id,
172            self.value as u8,
173            (self.value >> 8) as u8,
174        ]
175    }
176
177    pub fn deserialize(data: &[u8; 4]) -> Self {
178        NegiconModuleEventShortMessage {
179            sequence: data[0],
180            sub_id: data[1],
181            value: make_u16(data[3], data[2]),
182        }
183    }
184
185    pub fn deserialize_double(data: &[u8; 8]) -> (Self, Self) {
186        let first =
187            NegiconModuleEventShortMessage::deserialize(&[data[0], data[1], data[2], data[3]]);
188        let second =
189            NegiconModuleEventShortMessage::deserialize(&[data[4], data[5], data[6], data[7]]);
190        (first, second)
191    }
192
193    pub fn serialize_double(first: &Self, second: &Self) -> [u8; 8] {
194        let first_data = first.serialize();
195        let second_data = second.serialize();
196        [
197            first_data[0],
198            first_data[1],
199            first_data[2],
200            first_data[3],
201            second_data[0],
202            second_data[1],
203            second_data[2],
204            second_data[3],
205        ]
206    }
207}
208
209impl NegiconFrame {
210    pub fn new(
211        origin: u16,
212        destination: u16,
213        message_type: NegiconMessageType,
214        message_data: [u8; 8],
215    ) -> Self {
216        NegiconFrame {
217            origin,
218            destination,
219            message_type,
220            reserved: 0,
221            message_data,
222        }
223    }
224
225    pub fn ping(id: u16, module_type: NegiconModuleType, sequence: u8, fw_version: u16) -> Self {
226        let message = NegiconPingMessage {
227            sequence,
228            ttl: 8,
229            module_type,
230            fw_version,
231        };
232        let message_data = message.serialize();
233        NegiconFrame::new(id, 0, NegiconMessageType::Ping, message_data)
234    }
235
236    pub fn nop() -> Self {
237        NegiconFrame {
238            origin: 0,
239            destination: 0,
240            message_type: NegiconMessageType::Nop,
241            reserved: 0,
242            message_data: [0; 8],
243        }
244    }
245
246    pub fn serialize(&self) -> [u8; 16] {
247        let mut data = [
248            0u8,
249            0u8,
250            self.origin as u8,
251            (self.origin >> 8) as u8,
252            self.destination as u8,
253            (self.destination >> 8) as u8,
254            self.message_type as u8,
255            0u8,
256            self.message_data[0],
257            self.message_data[1],
258            self.message_data[2],
259            self.message_data[3],
260            self.message_data[4],
261            self.message_data[5],
262            self.message_data[6],
263            self.message_data[7],
264        ];
265        set_crc(&mut data);
266        data
267    }
268
269    pub fn is_ping(&self) -> bool {
270        self.message_type == NegiconMessageType::Ping
271    }
272
273    pub fn is_nop(&self) -> bool {
274        self.message_type == NegiconMessageType::Nop
275    }
276
277    pub fn serialize_u16(&self) -> [u16; 4] {
278        let bytes = self.serialize();
279        [
280            make_u16(bytes[0], bytes[1]),
281            make_u16(bytes[2], bytes[3]),
282            make_u16(bytes[4], bytes[5]),
283            make_u16(bytes[6], bytes[7]),
284        ]
285    }
286
287    pub fn serialize_u32(&self) -> [u32; 2] {
288        let bytes = self.serialize();
289        [
290            make_u32(bytes[0], bytes[1], bytes[2], bytes[3]),
291            make_u32(bytes[4], bytes[5], bytes[6], bytes[7]),
292        ]
293    }
294
295    pub fn deserialize(data: &[u8; 16]) -> Result<Self, InvalidMessage> {
296        verify_crc(data)?;
297        Ok(NegiconFrame {
298            origin: make_u16(data[2], data[3]),
299            destination: make_u16(data[4], data[5]),
300            message_type: NegiconMessageType::from_u8(data[6])?,
301            reserved: data[7],
302            message_data: [
303                data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15],
304            ],
305        })
306    }
307}