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 {
177 if !self.data_buffer.is_empty() {
178 let s = String::from_utf8_lossy(&self.data_buffer).into_owned();
179 events.push(RNodeEvent::FirmwareDetail(s));
180 self.data_buffer.clear();
181 }
182 }
183 self.in_frame = true;
185 self.command = kiss::CMD_UNKNOWN;
186 self.data_buffer.clear();
187 self.command_buffer.clear();
188 self.escape = false;
189 } else if byte == kiss::FEND {
190 self.in_frame = true;
192 self.command = kiss::CMD_UNKNOWN;
193 self.data_buffer.clear();
194 self.command_buffer.clear();
195 self.escape = false;
196 } else if self.in_frame {
197 if self.data_buffer.is_empty()
198 && self.command_buffer.is_empty()
199 && self.command == kiss::CMD_UNKNOWN
200 {
201 self.command = byte;
203 } else if self.command == kiss::CMD_DATA
204 || self.command == CMD_FW_DETAIL
205 || data_cmd_to_index(self.command).is_some()
206 {
207 if byte == kiss::FESC {
209 self.escape = true;
210 } else if self.escape {
211 match byte {
212 kiss::TFEND => self.data_buffer.push(kiss::FEND),
213 kiss::TFESC => self.data_buffer.push(kiss::FESC),
214 _ => self.data_buffer.push(byte),
215 }
216 self.escape = false;
217 } else {
218 self.data_buffer.push(byte);
219 }
220 } else {
221 let val = if byte == kiss::FESC {
223 self.escape = true;
224 continue;
225 } else if self.escape {
226 self.escape = false;
227 match byte {
228 kiss::TFEND => kiss::FEND,
229 kiss::TFESC => kiss::FESC,
230 _ => byte,
231 }
232 } else {
233 byte
234 };
235
236 self.command_buffer.push(val);
237 self.parse_command(&mut events);
238 }
239 }
240 }
241
242 events
243 }
244
245 fn parse_command(&mut self, events: &mut Vec<RNodeEvent>) {
247 let buf = &self.command_buffer;
248 match self.command {
249 CMD_DETECT => {
250 if buf.len() >= 1 {
251 events.push(RNodeEvent::Detected(buf[0] == DETECT_RESP));
252 self.command = kiss::CMD_UNKNOWN;
253 self.in_frame = false;
254 }
255 }
256 CMD_FW_VERSION => {
257 if buf.len() >= 2 {
258 events.push(RNodeEvent::FirmwareVersion {
259 major: buf[0],
260 minor: buf[1],
261 });
262 self.command = kiss::CMD_UNKNOWN;
263 self.in_frame = false;
264 }
265 }
266 CMD_PLATFORM => {
267 if buf.len() >= 1 {
268 events.push(RNodeEvent::Platform(buf[0]));
269 self.command = kiss::CMD_UNKNOWN;
270 self.in_frame = false;
271 }
272 }
273 CMD_MCU => {
274 if buf.len() >= 1 {
275 events.push(RNodeEvent::Mcu(buf[0]));
276 self.command = kiss::CMD_UNKNOWN;
277 self.in_frame = false;
278 }
279 }
280 CMD_INTERFACES => {
281 if buf.len() >= 2 {
282 events.push(RNodeEvent::InterfaceType {
283 index: buf[0],
284 type_byte: buf[1],
285 });
286 self.command = kiss::CMD_UNKNOWN;
287 self.in_frame = false;
288 }
289 }
290 CMD_FREQUENCY => {
291 if buf.len() >= 4 {
292 let freq = (buf[0] as u32) << 24
293 | (buf[1] as u32) << 16
294 | (buf[2] as u32) << 8
295 | buf[3] as u32;
296 events.push(RNodeEvent::Frequency(freq));
297 self.command = kiss::CMD_UNKNOWN;
298 self.in_frame = false;
299 }
300 }
301 CMD_BANDWIDTH => {
302 if buf.len() >= 4 {
303 let bw = (buf[0] as u32) << 24
304 | (buf[1] as u32) << 16
305 | (buf[2] as u32) << 8
306 | buf[3] as u32;
307 events.push(RNodeEvent::Bandwidth(bw));
308 self.command = kiss::CMD_UNKNOWN;
309 self.in_frame = false;
310 }
311 }
312 CMD_TXPOWER => {
313 if buf.len() >= 1 {
314 events.push(RNodeEvent::TxPower(buf[0] as i8));
315 self.command = kiss::CMD_UNKNOWN;
316 self.in_frame = false;
317 }
318 }
319 CMD_SF => {
320 if buf.len() >= 1 {
321 events.push(RNodeEvent::SpreadingFactor(buf[0]));
322 self.command = kiss::CMD_UNKNOWN;
323 self.in_frame = false;
324 }
325 }
326 CMD_CR => {
327 if buf.len() >= 1 {
328 events.push(RNodeEvent::CodingRate(buf[0]));
329 self.command = kiss::CMD_UNKNOWN;
330 self.in_frame = false;
331 }
332 }
333 CMD_RADIO_STATE => {
334 if buf.len() >= 1 {
335 events.push(RNodeEvent::RadioState(buf[0]));
336 self.command = kiss::CMD_UNKNOWN;
337 self.in_frame = false;
338 }
339 }
340 CMD_STAT_RSSI => {
341 if buf.len() >= 1 {
342 events.push(RNodeEvent::StatRssi(buf[0]));
343 self.command = kiss::CMD_UNKNOWN;
344 self.in_frame = false;
345 }
346 }
347 CMD_STAT_SNR => {
348 if buf.len() >= 1 {
349 events.push(RNodeEvent::StatSnr(buf[0] as i8));
350 self.command = kiss::CMD_UNKNOWN;
351 self.in_frame = false;
352 }
353 }
354 CMD_ST_ALOCK => {
355 if buf.len() >= 2 {
356 let val = (buf[0] as u16) << 8 | buf[1] as u16;
357 events.push(RNodeEvent::StAlock(val));
358 self.command = kiss::CMD_UNKNOWN;
359 self.in_frame = false;
360 }
361 }
362 CMD_LT_ALOCK => {
363 if buf.len() >= 2 {
364 let val = (buf[0] as u16) << 8 | buf[1] as u16;
365 events.push(RNodeEvent::LtAlock(val));
366 self.command = kiss::CMD_UNKNOWN;
367 self.in_frame = false;
368 }
369 }
370 CMD_READY => {
371 events.push(RNodeEvent::Ready);
372 self.command = kiss::CMD_UNKNOWN;
373 self.in_frame = false;
374 }
375 CMD_SEL_INT => {
376 if buf.len() >= 1 {
377 self.selected_index = buf[0];
378 events.push(RNodeEvent::SelectedInterface(buf[0]));
379 self.command = kiss::CMD_UNKNOWN;
380 self.in_frame = false;
381 }
382 }
383 CMD_ERROR => {
384 if buf.len() >= 1 {
385 events.push(RNodeEvent::Error(buf[0]));
386 self.command = kiss::CMD_UNKNOWN;
387 self.in_frame = false;
388 }
389 }
390 _ => {
391 }
393 }
394 }
395}
396
397impl Default for RNodeDecoder {
398 fn default() -> Self {
399 Self::new()
400 }
401}
402
403pub fn rnode_command(cmd: u8, value: &[u8]) -> Vec<u8> {
407 let escaped = kiss::escape(value);
408 let mut out = Vec::with_capacity(escaped.len() + 3);
409 out.push(kiss::FEND);
410 out.push(cmd);
411 out.extend_from_slice(&escaped);
412 out.push(kiss::FEND);
413 out
414}
415
416pub fn rnode_select_command(index: u8, cmd: u8, value: &[u8]) -> Vec<u8> {
419 let mut out = rnode_command(CMD_SEL_INT, &[index]);
420 out.extend_from_slice(&rnode_command(cmd, value));
421 out
422}
423
424pub fn detect_request() -> Vec<u8> {
426 rnode_command(CMD_DETECT, &[DETECT_REQ])
427}
428
429pub fn rnode_data_frame(index: u8, data: &[u8]) -> Vec<u8> {
432 let cmd = if (index as usize) < DATA_CMDS.len() {
433 DATA_CMDS[index as usize]
434 } else {
435 CMD_INT0_DATA
436 };
437 let escaped = kiss::escape(data);
438 let mut out = Vec::with_capacity(escaped.len() + 3);
439 out.push(kiss::FEND);
440 out.push(cmd);
441 out.extend_from_slice(&escaped);
442 out.push(kiss::FEND);
443 out
444}
445
446#[cfg(test)]
449mod tests {
450 use super::*;
451
452 #[test]
453 fn detect_request_format() {
454 let req = detect_request();
455 assert_eq!(req, vec![kiss::FEND, CMD_DETECT, DETECT_REQ, kiss::FEND]);
456 }
457
458 #[test]
459 fn decoder_detect_response() {
460 let response = vec![kiss::FEND, CMD_DETECT, DETECT_RESP, kiss::FEND];
461 let mut decoder = RNodeDecoder::new();
462 let events = decoder.feed(&response);
463 assert_eq!(events.len(), 1);
464 assert_eq!(events[0], RNodeEvent::Detected(true));
465 }
466
467 #[test]
468 fn decoder_firmware_version() {
469 let response = vec![kiss::FEND, CMD_FW_VERSION, 0x01, 0x34, kiss::FEND];
471 let mut decoder = RNodeDecoder::new();
472 let events = decoder.feed(&response);
473 assert_eq!(events.len(), 1);
474 assert_eq!(
475 events[0],
476 RNodeEvent::FirmwareVersion {
477 major: 1,
478 minor: 0x34
479 }
480 );
481 }
482
483 #[test]
484 fn decoder_platform() {
485 let response = vec![kiss::FEND, CMD_PLATFORM, 0x80, kiss::FEND]; let mut decoder = RNodeDecoder::new();
487 let events = decoder.feed(&response);
488 assert_eq!(events.len(), 1);
489 assert_eq!(events[0], RNodeEvent::Platform(0x80));
490 }
491
492 #[test]
493 fn decoder_interfaces() {
494 let response = vec![kiss::FEND, CMD_INTERFACES, 0x00, 0x01, kiss::FEND];
495 let mut decoder = RNodeDecoder::new();
496 let events = decoder.feed(&response);
497 assert_eq!(events.len(), 1);
498 assert_eq!(
499 events[0],
500 RNodeEvent::InterfaceType {
501 index: 0,
502 type_byte: 0x01
503 }
504 );
505 }
506
507 #[test]
508 fn decoder_frequency() {
509 let freq: u32 = 867_200_000;
512 let response = vec![
513 kiss::FEND,
514 CMD_FREQUENCY,
515 (freq >> 24) as u8,
516 (freq >> 16) as u8,
517 (freq >> 8) as u8,
518 (freq & 0xFF) as u8,
519 kiss::FEND,
520 ];
521 let mut decoder = RNodeDecoder::new();
522 let events = decoder.feed(&response);
523 assert_eq!(events.len(), 1);
524 assert_eq!(events[0], RNodeEvent::Frequency(867_200_000));
525 }
526
527 #[test]
528 fn decoder_data_frame_int0() {
529 let payload = vec![0x01, 0x02, 0x03, 0x04, 0x05];
530 let mut frame = vec![kiss::FEND, CMD_INT0_DATA];
532 frame.extend_from_slice(&kiss::escape(&payload));
533 frame.push(kiss::FEND);
534
535 let mut decoder = RNodeDecoder::new();
536 let events = decoder.feed(&frame);
537 assert_eq!(events.len(), 1);
538 assert_eq!(
539 events[0],
540 RNodeEvent::DataFrame {
541 index: 0,
542 data: payload
543 }
544 );
545 }
546
547 #[test]
548 fn decoder_multi_sub_data() {
549 let payload = vec![0xAA, 0xBB];
550 let mut frame = vec![kiss::FEND, CMD_INT1_DATA];
552 frame.extend_from_slice(&kiss::escape(&payload));
553 frame.push(kiss::FEND);
554
555 let mut decoder = RNodeDecoder::new();
556 let events = decoder.feed(&frame);
557 assert_eq!(events.len(), 1);
558 assert_eq!(
559 events[0],
560 RNodeEvent::DataFrame {
561 index: 1,
562 data: payload
563 }
564 );
565 }
566
567 #[test]
568 fn rnode_select_command_format() {
569 let freq: u32 = 868_000_000;
571 let freq_bytes = [
572 (freq >> 24) as u8,
573 (freq >> 16) as u8,
574 (freq >> 8) as u8,
575 (freq & 0xFF) as u8,
576 ];
577 let cmd = rnode_select_command(1, CMD_FREQUENCY, &freq_bytes);
578
579 assert_eq!(cmd[0], kiss::FEND);
581 assert_eq!(cmd[1], CMD_SEL_INT);
582 assert_eq!(cmd[2], 0x01);
583 assert_eq!(cmd[3], kiss::FEND);
584
585 assert_eq!(cmd[4], kiss::FEND);
587 assert_eq!(cmd[5], CMD_FREQUENCY);
588 }
589
590 #[test]
591 fn rnode_data_frame_format() {
592 let data = vec![0x01, 0x02, 0x03];
593 let frame = rnode_data_frame(0, &data);
594 assert_eq!(frame[0], kiss::FEND);
595 assert_eq!(frame[1], CMD_INT0_DATA);
596 assert_eq!(*frame.last().unwrap(), kiss::FEND);
597
598 let frame1 = rnode_data_frame(1, &data);
600 assert_eq!(frame1[1], CMD_INT1_DATA);
601
602 let frame2 = rnode_data_frame(2, &data);
604 assert_eq!(frame2[1], CMD_INT2_DATA);
605 }
606}