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_FW_DETAIL: u8 = 0x51;
31pub const CMD_RESET: u8 = 0x55;
32pub const CMD_INTERFACES: u8 = 0x71;
33pub const CMD_ERROR: u8 = 0x90;
34
35pub const DETECT_REQ: u8 = 0x73;
36pub const DETECT_RESP: u8 = 0x46;
37
38pub const RADIO_STATE_OFF: u8 = 0x00;
39pub const RADIO_STATE_ON: u8 = 0x01;
40
41const CMD_INT0_DATA: u8 = 0x00;
43const CMD_INT1_DATA: u8 = 0x10;
44const CMD_INT2_DATA: u8 = 0x20;
45const CMD_INT3_DATA: u8 = 0x70;
46const CMD_INT4_DATA: u8 = 0x75;
47const CMD_INT5_DATA: u8 = 0x90;
48const CMD_INT6_DATA: u8 = 0xA0;
49const CMD_INT7_DATA: u8 = 0xB0;
50const CMD_INT8_DATA: u8 = 0xC0;
51const CMD_INT9_DATA: u8 = 0xD0;
52const CMD_INT10_DATA: u8 = 0xE0;
53const CMD_INT11_DATA: u8 = 0xF0;
54
55const DATA_CMDS: [u8; 12] = [
57 CMD_INT0_DATA,
58 CMD_INT1_DATA,
59 CMD_INT2_DATA,
60 CMD_INT3_DATA,
61 CMD_INT4_DATA,
62 CMD_INT5_DATA,
63 CMD_INT6_DATA,
64 CMD_INT7_DATA,
65 CMD_INT8_DATA,
66 CMD_INT9_DATA,
67 CMD_INT10_DATA,
68 CMD_INT11_DATA,
69];
70
71fn data_cmd_to_index(cmd: u8) -> Option<usize> {
73 DATA_CMDS.iter().position(|&c| c == cmd)
74}
75
76#[derive(Debug, Clone, PartialEq)]
80pub enum RNodeEvent {
81 DataFrame { index: usize, data: Vec<u8> },
83 Detected(bool),
85 FirmwareVersion { major: u8, minor: u8 },
87 Platform(u8),
89 Mcu(u8),
91 InterfaceType { index: u8, type_byte: u8 },
93 Frequency(u32),
95 Bandwidth(u32),
97 TxPower(i8),
99 SpreadingFactor(u8),
101 CodingRate(u8),
103 RadioState(u8),
105 StatRssi(u8),
107 StatSnr(i8),
109 StAlock(u16),
111 LtAlock(u16),
113 Ready,
115 SelectedInterface(u8),
117 FirmwareDetail(String),
119 Error(u8),
121}
122
123pub struct RNodeDecoder {
130 in_frame: bool,
131 escape: bool,
132 command: u8,
133 data_buffer: Vec<u8>,
134 command_buffer: Vec<u8>,
135 selected_index: u8,
136}
137
138impl RNodeDecoder {
139 pub fn new() -> Self {
140 RNodeDecoder {
141 in_frame: false,
142 escape: false,
143 command: kiss::CMD_UNKNOWN,
144 data_buffer: Vec::new(),
145 command_buffer: Vec::new(),
146 selected_index: 0,
147 }
148 }
149
150 pub fn selected_index(&self) -> u8 {
152 self.selected_index
153 }
154
155 pub fn feed(&mut self, bytes: &[u8]) -> Vec<RNodeEvent> {
157 let mut events = Vec::new();
158
159 for &byte in bytes {
160 if self.in_frame && byte == kiss::FEND {
161 if let Some(idx) = data_cmd_to_index(self.command) {
163 if !self.data_buffer.is_empty() {
164 events.push(RNodeEvent::DataFrame {
165 index: idx,
166 data: core::mem::take(&mut self.data_buffer),
167 });
168 }
169 } else if self.command == kiss::CMD_DATA {
170 if !self.data_buffer.is_empty() {
171 events.push(RNodeEvent::DataFrame {
172 index: self.selected_index as usize,
173 data: core::mem::take(&mut self.data_buffer),
174 });
175 }
176 } else if self.command == CMD_FW_DETAIL && !self.data_buffer.is_empty() {
177 let s = String::from_utf8_lossy(&self.data_buffer).into_owned();
178 events.push(RNodeEvent::FirmwareDetail(s));
179 self.data_buffer.clear();
180 }
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 byte == kiss::FEND {
188 self.in_frame = true;
190 self.command = kiss::CMD_UNKNOWN;
191 self.data_buffer.clear();
192 self.command_buffer.clear();
193 self.escape = false;
194 } else if self.in_frame {
195 if self.data_buffer.is_empty()
196 && self.command_buffer.is_empty()
197 && self.command == kiss::CMD_UNKNOWN
198 {
199 self.command = byte;
201 } else if self.command == kiss::CMD_DATA
202 || self.command == CMD_FW_DETAIL
203 || data_cmd_to_index(self.command).is_some()
204 {
205 if byte == kiss::FESC {
207 self.escape = true;
208 } else if self.escape {
209 match byte {
210 kiss::TFEND => self.data_buffer.push(kiss::FEND),
211 kiss::TFESC => self.data_buffer.push(kiss::FESC),
212 _ => self.data_buffer.push(byte),
213 }
214 self.escape = false;
215 } else {
216 self.data_buffer.push(byte);
217 }
218 } else {
219 let val = if byte == kiss::FESC {
221 self.escape = true;
222 continue;
223 } else if self.escape {
224 self.escape = false;
225 match byte {
226 kiss::TFEND => kiss::FEND,
227 kiss::TFESC => kiss::FESC,
228 _ => byte,
229 }
230 } else {
231 byte
232 };
233
234 self.command_buffer.push(val);
235 self.parse_command(&mut events);
236 }
237 }
238 }
239
240 events
241 }
242
243 fn parse_command(&mut self, events: &mut Vec<RNodeEvent>) {
245 let buf = &self.command_buffer;
246 match self.command {
247 CMD_DETECT => {
248 if !buf.is_empty() {
249 events.push(RNodeEvent::Detected(buf[0] == DETECT_RESP));
250 self.command = kiss::CMD_UNKNOWN;
251 self.in_frame = false;
252 }
253 }
254 CMD_FW_VERSION => {
255 if buf.len() >= 2 {
256 events.push(RNodeEvent::FirmwareVersion {
257 major: buf[0],
258 minor: buf[1],
259 });
260 self.command = kiss::CMD_UNKNOWN;
261 self.in_frame = false;
262 }
263 }
264 CMD_PLATFORM => {
265 if !buf.is_empty() {
266 events.push(RNodeEvent::Platform(buf[0]));
267 self.command = kiss::CMD_UNKNOWN;
268 self.in_frame = false;
269 }
270 }
271 CMD_MCU => {
272 if !buf.is_empty() {
273 events.push(RNodeEvent::Mcu(buf[0]));
274 self.command = kiss::CMD_UNKNOWN;
275 self.in_frame = false;
276 }
277 }
278 CMD_INTERFACES => {
279 if buf.len() >= 2 {
280 events.push(RNodeEvent::InterfaceType {
281 index: buf[0],
282 type_byte: buf[1],
283 });
284 self.command = kiss::CMD_UNKNOWN;
285 self.in_frame = false;
286 }
287 }
288 CMD_FREQUENCY => {
289 if buf.len() >= 4 {
290 let freq = (buf[0] as u32) << 24
291 | (buf[1] as u32) << 16
292 | (buf[2] as u32) << 8
293 | buf[3] as u32;
294 events.push(RNodeEvent::Frequency(freq));
295 self.command = kiss::CMD_UNKNOWN;
296 self.in_frame = false;
297 }
298 }
299 CMD_BANDWIDTH => {
300 if buf.len() >= 4 {
301 let bw = (buf[0] as u32) << 24
302 | (buf[1] as u32) << 16
303 | (buf[2] as u32) << 8
304 | buf[3] as u32;
305 events.push(RNodeEvent::Bandwidth(bw));
306 self.command = kiss::CMD_UNKNOWN;
307 self.in_frame = false;
308 }
309 }
310 CMD_TXPOWER => {
311 if !buf.is_empty() {
312 events.push(RNodeEvent::TxPower(buf[0] as i8));
313 self.command = kiss::CMD_UNKNOWN;
314 self.in_frame = false;
315 }
316 }
317 CMD_SF => {
318 if !buf.is_empty() {
319 events.push(RNodeEvent::SpreadingFactor(buf[0]));
320 self.command = kiss::CMD_UNKNOWN;
321 self.in_frame = false;
322 }
323 }
324 CMD_CR => {
325 if !buf.is_empty() {
326 events.push(RNodeEvent::CodingRate(buf[0]));
327 self.command = kiss::CMD_UNKNOWN;
328 self.in_frame = false;
329 }
330 }
331 CMD_RADIO_STATE => {
332 if !buf.is_empty() {
333 events.push(RNodeEvent::RadioState(buf[0]));
334 self.command = kiss::CMD_UNKNOWN;
335 self.in_frame = false;
336 }
337 }
338 CMD_STAT_RSSI => {
339 if !buf.is_empty() {
340 events.push(RNodeEvent::StatRssi(buf[0]));
341 self.command = kiss::CMD_UNKNOWN;
342 self.in_frame = false;
343 }
344 }
345 CMD_STAT_SNR => {
346 if !buf.is_empty() {
347 events.push(RNodeEvent::StatSnr(buf[0] as i8));
348 self.command = kiss::CMD_UNKNOWN;
349 self.in_frame = false;
350 }
351 }
352 CMD_ST_ALOCK => {
353 if buf.len() >= 2 {
354 let val = (buf[0] as u16) << 8 | buf[1] as u16;
355 events.push(RNodeEvent::StAlock(val));
356 self.command = kiss::CMD_UNKNOWN;
357 self.in_frame = false;
358 }
359 }
360 CMD_LT_ALOCK => {
361 if buf.len() >= 2 {
362 let val = (buf[0] as u16) << 8 | buf[1] as u16;
363 events.push(RNodeEvent::LtAlock(val));
364 self.command = kiss::CMD_UNKNOWN;
365 self.in_frame = false;
366 }
367 }
368 CMD_READY => {
369 events.push(RNodeEvent::Ready);
370 self.command = kiss::CMD_UNKNOWN;
371 self.in_frame = false;
372 }
373 CMD_SEL_INT => {
374 if !buf.is_empty() {
375 self.selected_index = buf[0];
376 events.push(RNodeEvent::SelectedInterface(buf[0]));
377 self.command = kiss::CMD_UNKNOWN;
378 self.in_frame = false;
379 }
380 }
381 CMD_ERROR if !buf.is_empty() => {
382 events.push(RNodeEvent::Error(buf[0]));
383 self.command = kiss::CMD_UNKNOWN;
384 self.in_frame = false;
385 }
386 _ => {
387 }
389 }
390 }
391}
392
393impl Default for RNodeDecoder {
394 fn default() -> Self {
395 Self::new()
396 }
397}
398
399pub fn rnode_command(cmd: u8, value: &[u8]) -> Vec<u8> {
403 let escaped = kiss::escape(value);
404 let mut out = Vec::with_capacity(escaped.len() + 3);
405 out.push(kiss::FEND);
406 out.push(cmd);
407 out.extend_from_slice(&escaped);
408 out.push(kiss::FEND);
409 out
410}
411
412pub fn rnode_select_command(index: u8, cmd: u8, value: &[u8]) -> Vec<u8> {
415 let mut out = rnode_command(CMD_SEL_INT, &[index]);
416 out.extend_from_slice(&rnode_command(cmd, value));
417 out
418}
419
420pub fn detect_request() -> Vec<u8> {
422 rnode_command(CMD_DETECT, &[DETECT_REQ])
423}
424
425pub fn rnode_data_frame(index: u8, data: &[u8]) -> Vec<u8> {
428 let cmd = if (index as usize) < DATA_CMDS.len() {
429 DATA_CMDS[index as usize]
430 } else {
431 CMD_INT0_DATA
432 };
433 let escaped = kiss::escape(data);
434 let mut out = Vec::with_capacity(escaped.len() + 3);
435 out.push(kiss::FEND);
436 out.push(cmd);
437 out.extend_from_slice(&escaped);
438 out.push(kiss::FEND);
439 out
440}
441
442pub fn rnode_multi_data_frame(index: u8, data: &[u8]) -> Vec<u8> {
446 rnode_select_command(index, kiss::CMD_DATA, data)
447}
448
449#[cfg(test)]
452mod tests {
453 use super::*;
454
455 #[test]
456 fn detect_request_format() {
457 let req = detect_request();
458 assert_eq!(req, vec![kiss::FEND, CMD_DETECT, DETECT_REQ, kiss::FEND]);
459 }
460
461 #[test]
462 fn decoder_detect_response() {
463 let response = vec![kiss::FEND, CMD_DETECT, DETECT_RESP, kiss::FEND];
464 let mut decoder = RNodeDecoder::new();
465 let events = decoder.feed(&response);
466 assert_eq!(events.len(), 1);
467 assert_eq!(events[0], RNodeEvent::Detected(true));
468 }
469
470 #[test]
471 fn decoder_firmware_version() {
472 let response = vec![kiss::FEND, CMD_FW_VERSION, 0x01, 0x34, kiss::FEND];
474 let mut decoder = RNodeDecoder::new();
475 let events = decoder.feed(&response);
476 assert_eq!(events.len(), 1);
477 assert_eq!(
478 events[0],
479 RNodeEvent::FirmwareVersion {
480 major: 1,
481 minor: 0x34
482 }
483 );
484 }
485
486 #[test]
487 fn decoder_platform() {
488 let response = vec![kiss::FEND, CMD_PLATFORM, 0x80, kiss::FEND]; let mut decoder = RNodeDecoder::new();
490 let events = decoder.feed(&response);
491 assert_eq!(events.len(), 1);
492 assert_eq!(events[0], RNodeEvent::Platform(0x80));
493 }
494
495 #[test]
496 fn decoder_interfaces() {
497 let response = vec![kiss::FEND, CMD_INTERFACES, 0x00, 0x01, kiss::FEND];
498 let mut decoder = RNodeDecoder::new();
499 let events = decoder.feed(&response);
500 assert_eq!(events.len(), 1);
501 assert_eq!(
502 events[0],
503 RNodeEvent::InterfaceType {
504 index: 0,
505 type_byte: 0x01
506 }
507 );
508 }
509
510 #[test]
511 fn decoder_frequency() {
512 let freq: u32 = 867_200_000;
515 let response = vec![
516 kiss::FEND,
517 CMD_FREQUENCY,
518 (freq >> 24) as u8,
519 (freq >> 16) as u8,
520 (freq >> 8) as u8,
521 (freq & 0xFF) as u8,
522 kiss::FEND,
523 ];
524 let mut decoder = RNodeDecoder::new();
525 let events = decoder.feed(&response);
526 assert_eq!(events.len(), 1);
527 assert_eq!(events[0], RNodeEvent::Frequency(867_200_000));
528 }
529
530 #[test]
531 fn decoder_data_frame_int0() {
532 let payload = vec![0x01, 0x02, 0x03, 0x04, 0x05];
533 let mut frame = vec![kiss::FEND, CMD_INT0_DATA];
535 frame.extend_from_slice(&kiss::escape(&payload));
536 frame.push(kiss::FEND);
537
538 let mut decoder = RNodeDecoder::new();
539 let events = decoder.feed(&frame);
540 assert_eq!(events.len(), 1);
541 assert_eq!(
542 events[0],
543 RNodeEvent::DataFrame {
544 index: 0,
545 data: payload
546 }
547 );
548 }
549
550 #[test]
551 fn decoder_multi_sub_data() {
552 let payload = vec![0xAA, 0xBB];
553 let mut frame = vec![kiss::FEND, CMD_INT1_DATA];
555 frame.extend_from_slice(&kiss::escape(&payload));
556 frame.push(kiss::FEND);
557
558 let mut decoder = RNodeDecoder::new();
559 let events = decoder.feed(&frame);
560 assert_eq!(events.len(), 1);
561 assert_eq!(
562 events[0],
563 RNodeEvent::DataFrame {
564 index: 1,
565 data: payload
566 }
567 );
568 }
569
570 #[test]
571 fn rnode_select_command_format() {
572 let freq: u32 = 868_000_000;
574 let freq_bytes = [
575 (freq >> 24) as u8,
576 (freq >> 16) as u8,
577 (freq >> 8) as u8,
578 (freq & 0xFF) as u8,
579 ];
580 let cmd = rnode_select_command(1, CMD_FREQUENCY, &freq_bytes);
581
582 assert_eq!(cmd[0], kiss::FEND);
584 assert_eq!(cmd[1], CMD_SEL_INT);
585 assert_eq!(cmd[2], 0x01);
586 assert_eq!(cmd[3], kiss::FEND);
587
588 assert_eq!(cmd[4], kiss::FEND);
590 assert_eq!(cmd[5], CMD_FREQUENCY);
591 }
592
593 #[test]
594 fn rnode_data_frame_format() {
595 let data = vec![0x01, 0x02, 0x03];
596 let frame = rnode_data_frame(0, &data);
597 assert_eq!(frame[0], kiss::FEND);
598 assert_eq!(frame[1], CMD_INT0_DATA);
599 assert_eq!(*frame.last().unwrap(), kiss::FEND);
600
601 let frame1 = rnode_data_frame(1, &data);
603 assert_eq!(frame1[1], CMD_INT1_DATA);
604
605 let frame2 = rnode_data_frame(2, &data);
607 assert_eq!(frame2[1], CMD_INT2_DATA);
608 }
609
610 #[test]
611 fn rnode_multi_data_frame_selects_actual_virtual_port() {
612 let frame = rnode_multi_data_frame(7, &[1, 2, 3]);
613 assert_eq!(
614 frame,
615 vec![
616 kiss::FEND,
617 CMD_SEL_INT,
618 7,
619 kiss::FEND,
620 kiss::FEND,
621 kiss::CMD_DATA,
622 1,
623 2,
624 3,
625 kiss::FEND,
626 ]
627 );
628 }
629}