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}