1use crate::kiss;
8
9pub const CMD_FREQUENCY: u8 = 0x01;
12pub const CMD_BANDWIDTH: u8 = 0x02;
13pub const CMD_TXPOWER: u8 = 0x03;
14pub const CMD_SF: u8 = 0x04;
15pub const CMD_CR: u8 = 0x05;
16pub const CMD_RADIO_STATE: u8 = 0x06;
17pub const CMD_RADIO_LOCK: u8 = 0x07;
18pub const CMD_DETECT: u8 = 0x08;
19pub const CMD_LEAVE: u8 = 0x0A;
20pub const CMD_ST_ALOCK: u8 = 0x0B;
21pub const CMD_LT_ALOCK: u8 = 0x0C;
22pub const CMD_READY: u8 = 0x0F;
23pub const CMD_SEL_INT: u8 = 0x1F;
24pub const CMD_STAT_RSSI: u8 = 0x23;
25pub const CMD_STAT_SNR: u8 = 0x24;
26pub const CMD_RANDOM: u8 = 0x40;
27pub const CMD_PLATFORM: u8 = 0x48;
28pub const CMD_MCU: u8 = 0x49;
29pub const CMD_FW_VERSION: u8 = 0x50;
30pub const CMD_RESET: u8 = 0x55;
31pub const CMD_INTERFACES: u8 = 0x71;
32pub const CMD_ERROR: u8 = 0x90;
33
34pub const DETECT_REQ: u8 = 0x73;
35pub const DETECT_RESP: u8 = 0x46;
36
37pub const RADIO_STATE_OFF: u8 = 0x00;
38pub const RADIO_STATE_ON: u8 = 0x01;
39
40const CMD_INT0_DATA: u8 = 0x00;
42const CMD_INT1_DATA: u8 = 0x10;
43const CMD_INT2_DATA: u8 = 0x20;
44const CMD_INT3_DATA: u8 = 0x70;
45const CMD_INT4_DATA: u8 = 0x75;
46const CMD_INT5_DATA: u8 = 0x90;
47const CMD_INT6_DATA: u8 = 0xA0;
48const CMD_INT7_DATA: u8 = 0xB0;
49const CMD_INT8_DATA: u8 = 0xC0;
50const CMD_INT9_DATA: u8 = 0xD0;
51const CMD_INT10_DATA: u8 = 0xE0;
52const CMD_INT11_DATA: u8 = 0xF0;
53
54const DATA_CMDS: [u8; 12] = [
56 CMD_INT0_DATA,
57 CMD_INT1_DATA,
58 CMD_INT2_DATA,
59 CMD_INT3_DATA,
60 CMD_INT4_DATA,
61 CMD_INT5_DATA,
62 CMD_INT6_DATA,
63 CMD_INT7_DATA,
64 CMD_INT8_DATA,
65 CMD_INT9_DATA,
66 CMD_INT10_DATA,
67 CMD_INT11_DATA,
68];
69
70fn data_cmd_to_index(cmd: u8) -> Option<usize> {
72 DATA_CMDS.iter().position(|&c| c == cmd)
73}
74
75#[derive(Debug, Clone, PartialEq)]
79pub enum RNodeEvent {
80 DataFrame { index: usize, data: Vec<u8> },
82 Detected(bool),
84 FirmwareVersion { major: u8, minor: u8 },
86 Platform(u8),
88 Mcu(u8),
90 InterfaceType { index: u8, type_byte: u8 },
92 Frequency(u32),
94 Bandwidth(u32),
96 TxPower(i8),
98 SpreadingFactor(u8),
100 CodingRate(u8),
102 RadioState(u8),
104 StatRssi(u8),
106 StatSnr(i8),
108 StAlock(u16),
110 LtAlock(u16),
112 Ready,
114 SelectedInterface(u8),
116 Error(u8),
118}
119
120pub struct RNodeDecoder {
127 in_frame: bool,
128 escape: bool,
129 command: u8,
130 data_buffer: Vec<u8>,
131 command_buffer: Vec<u8>,
132 selected_index: u8,
133}
134
135impl RNodeDecoder {
136 pub fn new() -> Self {
137 RNodeDecoder {
138 in_frame: false,
139 escape: false,
140 command: kiss::CMD_UNKNOWN,
141 data_buffer: Vec::new(),
142 command_buffer: Vec::new(),
143 selected_index: 0,
144 }
145 }
146
147 pub fn selected_index(&self) -> u8 {
149 self.selected_index
150 }
151
152 pub fn feed(&mut self, bytes: &[u8]) -> Vec<RNodeEvent> {
154 let mut events = Vec::new();
155
156 for &byte in bytes {
157 if self.in_frame && byte == kiss::FEND {
158 if let Some(idx) = data_cmd_to_index(self.command) {
160 if !self.data_buffer.is_empty() {
161 events.push(RNodeEvent::DataFrame {
162 index: idx,
163 data: core::mem::take(&mut self.data_buffer),
164 });
165 }
166 } else if self.command == kiss::CMD_DATA {
167 if !self.data_buffer.is_empty() {
168 events.push(RNodeEvent::DataFrame {
169 index: self.selected_index as usize,
170 data: core::mem::take(&mut self.data_buffer),
171 });
172 }
173 }
174 self.in_frame = true;
176 self.command = kiss::CMD_UNKNOWN;
177 self.data_buffer.clear();
178 self.command_buffer.clear();
179 self.escape = false;
180 } else if byte == kiss::FEND {
181 self.in_frame = true;
183 self.command = kiss::CMD_UNKNOWN;
184 self.data_buffer.clear();
185 self.command_buffer.clear();
186 self.escape = false;
187 } else if self.in_frame {
188 if self.data_buffer.is_empty()
189 && self.command_buffer.is_empty()
190 && self.command == kiss::CMD_UNKNOWN
191 {
192 self.command = byte;
194 } else if self.command == kiss::CMD_DATA
195 || data_cmd_to_index(self.command).is_some()
196 {
197 if byte == kiss::FESC {
199 self.escape = true;
200 } else if self.escape {
201 match byte {
202 kiss::TFEND => self.data_buffer.push(kiss::FEND),
203 kiss::TFESC => self.data_buffer.push(kiss::FESC),
204 _ => self.data_buffer.push(byte),
205 }
206 self.escape = false;
207 } else {
208 self.data_buffer.push(byte);
209 }
210 } else {
211 let val = if byte == kiss::FESC {
213 self.escape = true;
214 continue;
215 } else if self.escape {
216 self.escape = false;
217 match byte {
218 kiss::TFEND => kiss::FEND,
219 kiss::TFESC => kiss::FESC,
220 _ => byte,
221 }
222 } else {
223 byte
224 };
225
226 self.command_buffer.push(val);
227 self.parse_command(&mut events);
228 }
229 }
230 }
231
232 events
233 }
234
235 fn parse_command(&mut self, events: &mut Vec<RNodeEvent>) {
237 let buf = &self.command_buffer;
238 match self.command {
239 CMD_DETECT => {
240 if buf.len() >= 1 {
241 events.push(RNodeEvent::Detected(buf[0] == DETECT_RESP));
242 self.command = kiss::CMD_UNKNOWN;
243 self.in_frame = false;
244 }
245 }
246 CMD_FW_VERSION => {
247 if buf.len() >= 2 {
248 events.push(RNodeEvent::FirmwareVersion {
249 major: buf[0],
250 minor: buf[1],
251 });
252 self.command = kiss::CMD_UNKNOWN;
253 self.in_frame = false;
254 }
255 }
256 CMD_PLATFORM => {
257 if buf.len() >= 1 {
258 events.push(RNodeEvent::Platform(buf[0]));
259 self.command = kiss::CMD_UNKNOWN;
260 self.in_frame = false;
261 }
262 }
263 CMD_MCU => {
264 if buf.len() >= 1 {
265 events.push(RNodeEvent::Mcu(buf[0]));
266 self.command = kiss::CMD_UNKNOWN;
267 self.in_frame = false;
268 }
269 }
270 CMD_INTERFACES => {
271 if buf.len() >= 2 {
272 events.push(RNodeEvent::InterfaceType {
273 index: buf[0],
274 type_byte: buf[1],
275 });
276 self.command = kiss::CMD_UNKNOWN;
277 self.in_frame = false;
278 }
279 }
280 CMD_FREQUENCY => {
281 if buf.len() >= 4 {
282 let freq = (buf[0] as u32) << 24
283 | (buf[1] as u32) << 16
284 | (buf[2] as u32) << 8
285 | buf[3] as u32;
286 events.push(RNodeEvent::Frequency(freq));
287 self.command = kiss::CMD_UNKNOWN;
288 self.in_frame = false;
289 }
290 }
291 CMD_BANDWIDTH => {
292 if buf.len() >= 4 {
293 let bw = (buf[0] as u32) << 24
294 | (buf[1] as u32) << 16
295 | (buf[2] as u32) << 8
296 | buf[3] as u32;
297 events.push(RNodeEvent::Bandwidth(bw));
298 self.command = kiss::CMD_UNKNOWN;
299 self.in_frame = false;
300 }
301 }
302 CMD_TXPOWER => {
303 if buf.len() >= 1 {
304 events.push(RNodeEvent::TxPower(buf[0] as i8));
305 self.command = kiss::CMD_UNKNOWN;
306 self.in_frame = false;
307 }
308 }
309 CMD_SF => {
310 if buf.len() >= 1 {
311 events.push(RNodeEvent::SpreadingFactor(buf[0]));
312 self.command = kiss::CMD_UNKNOWN;
313 self.in_frame = false;
314 }
315 }
316 CMD_CR => {
317 if buf.len() >= 1 {
318 events.push(RNodeEvent::CodingRate(buf[0]));
319 self.command = kiss::CMD_UNKNOWN;
320 self.in_frame = false;
321 }
322 }
323 CMD_RADIO_STATE => {
324 if buf.len() >= 1 {
325 events.push(RNodeEvent::RadioState(buf[0]));
326 self.command = kiss::CMD_UNKNOWN;
327 self.in_frame = false;
328 }
329 }
330 CMD_STAT_RSSI => {
331 if buf.len() >= 1 {
332 events.push(RNodeEvent::StatRssi(buf[0]));
333 self.command = kiss::CMD_UNKNOWN;
334 self.in_frame = false;
335 }
336 }
337 CMD_STAT_SNR => {
338 if buf.len() >= 1 {
339 events.push(RNodeEvent::StatSnr(buf[0] as i8));
340 self.command = kiss::CMD_UNKNOWN;
341 self.in_frame = false;
342 }
343 }
344 CMD_ST_ALOCK => {
345 if buf.len() >= 2 {
346 let val = (buf[0] as u16) << 8 | buf[1] as u16;
347 events.push(RNodeEvent::StAlock(val));
348 self.command = kiss::CMD_UNKNOWN;
349 self.in_frame = false;
350 }
351 }
352 CMD_LT_ALOCK => {
353 if buf.len() >= 2 {
354 let val = (buf[0] as u16) << 8 | buf[1] as u16;
355 events.push(RNodeEvent::LtAlock(val));
356 self.command = kiss::CMD_UNKNOWN;
357 self.in_frame = false;
358 }
359 }
360 CMD_READY => {
361 events.push(RNodeEvent::Ready);
362 self.command = kiss::CMD_UNKNOWN;
363 self.in_frame = false;
364 }
365 CMD_SEL_INT => {
366 if buf.len() >= 1 {
367 self.selected_index = buf[0];
368 events.push(RNodeEvent::SelectedInterface(buf[0]));
369 self.command = kiss::CMD_UNKNOWN;
370 self.in_frame = false;
371 }
372 }
373 CMD_ERROR => {
374 if buf.len() >= 1 {
375 events.push(RNodeEvent::Error(buf[0]));
376 self.command = kiss::CMD_UNKNOWN;
377 self.in_frame = false;
378 }
379 }
380 _ => {
381 }
383 }
384 }
385}
386
387pub fn rnode_command(cmd: u8, value: &[u8]) -> Vec<u8> {
391 let escaped = kiss::escape(value);
392 let mut out = Vec::with_capacity(escaped.len() + 3);
393 out.push(kiss::FEND);
394 out.push(cmd);
395 out.extend_from_slice(&escaped);
396 out.push(kiss::FEND);
397 out
398}
399
400pub fn rnode_select_command(index: u8, cmd: u8, value: &[u8]) -> Vec<u8> {
403 let mut out = rnode_command(CMD_SEL_INT, &[index]);
404 out.extend_from_slice(&rnode_command(cmd, value));
405 out
406}
407
408pub fn detect_request() -> Vec<u8> {
410 rnode_command(CMD_DETECT, &[DETECT_REQ])
411}
412
413pub fn rnode_data_frame(index: u8, data: &[u8]) -> Vec<u8> {
416 let cmd = if (index as usize) < DATA_CMDS.len() {
417 DATA_CMDS[index as usize]
418 } else {
419 CMD_INT0_DATA
420 };
421 let escaped = kiss::escape(data);
422 let mut out = Vec::with_capacity(escaped.len() + 3);
423 out.push(kiss::FEND);
424 out.push(cmd);
425 out.extend_from_slice(&escaped);
426 out.push(kiss::FEND);
427 out
428}
429
430#[cfg(test)]
433mod tests {
434 use super::*;
435
436 #[test]
437 fn detect_request_format() {
438 let req = detect_request();
439 assert_eq!(req, vec![kiss::FEND, CMD_DETECT, DETECT_REQ, kiss::FEND]);
440 }
441
442 #[test]
443 fn decoder_detect_response() {
444 let response = vec![kiss::FEND, CMD_DETECT, DETECT_RESP, kiss::FEND];
445 let mut decoder = RNodeDecoder::new();
446 let events = decoder.feed(&response);
447 assert_eq!(events.len(), 1);
448 assert_eq!(events[0], RNodeEvent::Detected(true));
449 }
450
451 #[test]
452 fn decoder_firmware_version() {
453 let response = vec![kiss::FEND, CMD_FW_VERSION, 0x01, 0x34, kiss::FEND];
455 let mut decoder = RNodeDecoder::new();
456 let events = decoder.feed(&response);
457 assert_eq!(events.len(), 1);
458 assert_eq!(
459 events[0],
460 RNodeEvent::FirmwareVersion {
461 major: 1,
462 minor: 0x34
463 }
464 );
465 }
466
467 #[test]
468 fn decoder_platform() {
469 let response = vec![kiss::FEND, CMD_PLATFORM, 0x80, kiss::FEND]; let mut decoder = RNodeDecoder::new();
471 let events = decoder.feed(&response);
472 assert_eq!(events.len(), 1);
473 assert_eq!(events[0], RNodeEvent::Platform(0x80));
474 }
475
476 #[test]
477 fn decoder_interfaces() {
478 let response = vec![kiss::FEND, CMD_INTERFACES, 0x00, 0x01, kiss::FEND];
479 let mut decoder = RNodeDecoder::new();
480 let events = decoder.feed(&response);
481 assert_eq!(events.len(), 1);
482 assert_eq!(
483 events[0],
484 RNodeEvent::InterfaceType {
485 index: 0,
486 type_byte: 0x01
487 }
488 );
489 }
490
491 #[test]
492 fn decoder_frequency() {
493 let freq: u32 = 867_200_000;
496 let response = vec![
497 kiss::FEND,
498 CMD_FREQUENCY,
499 (freq >> 24) as u8,
500 (freq >> 16) as u8,
501 (freq >> 8) as u8,
502 (freq & 0xFF) as u8,
503 kiss::FEND,
504 ];
505 let mut decoder = RNodeDecoder::new();
506 let events = decoder.feed(&response);
507 assert_eq!(events.len(), 1);
508 assert_eq!(events[0], RNodeEvent::Frequency(867_200_000));
509 }
510
511 #[test]
512 fn decoder_data_frame_int0() {
513 let payload = vec![0x01, 0x02, 0x03, 0x04, 0x05];
514 let mut frame = vec![kiss::FEND, CMD_INT0_DATA];
516 frame.extend_from_slice(&kiss::escape(&payload));
517 frame.push(kiss::FEND);
518
519 let mut decoder = RNodeDecoder::new();
520 let events = decoder.feed(&frame);
521 assert_eq!(events.len(), 1);
522 assert_eq!(
523 events[0],
524 RNodeEvent::DataFrame {
525 index: 0,
526 data: payload
527 }
528 );
529 }
530
531 #[test]
532 fn decoder_multi_sub_data() {
533 let payload = vec![0xAA, 0xBB];
534 let mut frame = vec![kiss::FEND, CMD_INT1_DATA];
536 frame.extend_from_slice(&kiss::escape(&payload));
537 frame.push(kiss::FEND);
538
539 let mut decoder = RNodeDecoder::new();
540 let events = decoder.feed(&frame);
541 assert_eq!(events.len(), 1);
542 assert_eq!(
543 events[0],
544 RNodeEvent::DataFrame {
545 index: 1,
546 data: payload
547 }
548 );
549 }
550
551 #[test]
552 fn rnode_select_command_format() {
553 let freq: u32 = 868_000_000;
555 let freq_bytes = [
556 (freq >> 24) as u8,
557 (freq >> 16) as u8,
558 (freq >> 8) as u8,
559 (freq & 0xFF) as u8,
560 ];
561 let cmd = rnode_select_command(1, CMD_FREQUENCY, &freq_bytes);
562
563 assert_eq!(cmd[0], kiss::FEND);
565 assert_eq!(cmd[1], CMD_SEL_INT);
566 assert_eq!(cmd[2], 0x01);
567 assert_eq!(cmd[3], kiss::FEND);
568
569 assert_eq!(cmd[4], kiss::FEND);
571 assert_eq!(cmd[5], CMD_FREQUENCY);
572 }
573
574 #[test]
575 fn rnode_data_frame_format() {
576 let data = vec![0x01, 0x02, 0x03];
577 let frame = rnode_data_frame(0, &data);
578 assert_eq!(frame[0], kiss::FEND);
579 assert_eq!(frame[1], CMD_INT0_DATA);
580 assert_eq!(*frame.last().unwrap(), kiss::FEND);
581
582 let frame1 = rnode_data_frame(1, &data);
584 assert_eq!(frame1[1], CMD_INT1_DATA);
585
586 let frame2 = rnode_data_frame(2, &data);
588 assert_eq!(frame2[1], CMD_INT2_DATA);
589 }
590}