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, CMD_INT1_DATA, CMD_INT2_DATA, CMD_INT3_DATA,
57 CMD_INT4_DATA, CMD_INT5_DATA, CMD_INT6_DATA, CMD_INT7_DATA,
58 CMD_INT8_DATA, CMD_INT9_DATA, CMD_INT10_DATA, CMD_INT11_DATA,
59];
60
61fn data_cmd_to_index(cmd: u8) -> Option<usize> {
63 DATA_CMDS.iter().position(|&c| c == cmd)
64}
65
66#[derive(Debug, Clone, PartialEq)]
70pub enum RNodeEvent {
71 DataFrame { index: usize, data: Vec<u8> },
73 Detected(bool),
75 FirmwareVersion { major: u8, minor: u8 },
77 Platform(u8),
79 Mcu(u8),
81 InterfaceType { index: u8, type_byte: u8 },
83 Frequency(u32),
85 Bandwidth(u32),
87 TxPower(i8),
89 SpreadingFactor(u8),
91 CodingRate(u8),
93 RadioState(u8),
95 StatRssi(u8),
97 StatSnr(i8),
99 StAlock(u16),
101 LtAlock(u16),
103 Ready,
105 SelectedInterface(u8),
107 Error(u8),
109}
110
111pub struct RNodeDecoder {
118 in_frame: bool,
119 escape: bool,
120 command: u8,
121 data_buffer: Vec<u8>,
122 command_buffer: Vec<u8>,
123 selected_index: u8,
124}
125
126impl RNodeDecoder {
127 pub fn new() -> Self {
128 RNodeDecoder {
129 in_frame: false,
130 escape: false,
131 command: kiss::CMD_UNKNOWN,
132 data_buffer: Vec::new(),
133 command_buffer: Vec::new(),
134 selected_index: 0,
135 }
136 }
137
138 pub fn selected_index(&self) -> u8 {
140 self.selected_index
141 }
142
143 pub fn feed(&mut self, bytes: &[u8]) -> Vec<RNodeEvent> {
145 let mut events = Vec::new();
146
147 for &byte in bytes {
148 if self.in_frame && byte == kiss::FEND {
149 if let Some(idx) = data_cmd_to_index(self.command) {
151 if !self.data_buffer.is_empty() {
152 events.push(RNodeEvent::DataFrame {
153 index: idx,
154 data: core::mem::take(&mut self.data_buffer),
155 });
156 }
157 } else if self.command == kiss::CMD_DATA {
158 if !self.data_buffer.is_empty() {
159 events.push(RNodeEvent::DataFrame {
160 index: self.selected_index as usize,
161 data: core::mem::take(&mut self.data_buffer),
162 });
163 }
164 }
165 self.in_frame = true;
167 self.command = kiss::CMD_UNKNOWN;
168 self.data_buffer.clear();
169 self.command_buffer.clear();
170 self.escape = false;
171 } else if byte == kiss::FEND {
172 self.in_frame = true;
174 self.command = kiss::CMD_UNKNOWN;
175 self.data_buffer.clear();
176 self.command_buffer.clear();
177 self.escape = false;
178 } else if self.in_frame {
179 if self.data_buffer.is_empty()
180 && self.command_buffer.is_empty()
181 && self.command == kiss::CMD_UNKNOWN
182 {
183 self.command = byte;
185 } else if self.command == kiss::CMD_DATA || data_cmd_to_index(self.command).is_some()
186 {
187 if byte == kiss::FESC {
189 self.escape = true;
190 } else if self.escape {
191 match byte {
192 kiss::TFEND => self.data_buffer.push(kiss::FEND),
193 kiss::TFESC => self.data_buffer.push(kiss::FESC),
194 _ => self.data_buffer.push(byte),
195 }
196 self.escape = false;
197 } else {
198 self.data_buffer.push(byte);
199 }
200 } else {
201 let val = if byte == kiss::FESC {
203 self.escape = true;
204 continue;
205 } else if self.escape {
206 self.escape = false;
207 match byte {
208 kiss::TFEND => kiss::FEND,
209 kiss::TFESC => kiss::FESC,
210 _ => byte,
211 }
212 } else {
213 byte
214 };
215
216 self.command_buffer.push(val);
217 self.parse_command(&mut events);
218 }
219 }
220 }
221
222 events
223 }
224
225 fn parse_command(&mut self, events: &mut Vec<RNodeEvent>) {
227 let buf = &self.command_buffer;
228 match self.command {
229 CMD_DETECT => {
230 if buf.len() >= 1 {
231 events.push(RNodeEvent::Detected(buf[0] == DETECT_RESP));
232 self.command = kiss::CMD_UNKNOWN;
233 self.in_frame = false;
234 }
235 }
236 CMD_FW_VERSION => {
237 if buf.len() >= 2 {
238 events.push(RNodeEvent::FirmwareVersion {
239 major: buf[0],
240 minor: buf[1],
241 });
242 self.command = kiss::CMD_UNKNOWN;
243 self.in_frame = false;
244 }
245 }
246 CMD_PLATFORM => {
247 if buf.len() >= 1 {
248 events.push(RNodeEvent::Platform(buf[0]));
249 self.command = kiss::CMD_UNKNOWN;
250 self.in_frame = false;
251 }
252 }
253 CMD_MCU => {
254 if buf.len() >= 1 {
255 events.push(RNodeEvent::Mcu(buf[0]));
256 self.command = kiss::CMD_UNKNOWN;
257 self.in_frame = false;
258 }
259 }
260 CMD_INTERFACES => {
261 if buf.len() >= 2 {
262 events.push(RNodeEvent::InterfaceType {
263 index: buf[0],
264 type_byte: buf[1],
265 });
266 self.command = kiss::CMD_UNKNOWN;
267 self.in_frame = false;
268 }
269 }
270 CMD_FREQUENCY => {
271 if buf.len() >= 4 {
272 let freq =
273 (buf[0] as u32) << 24 | (buf[1] as u32) << 16 | (buf[2] as u32) << 8 | buf[3] as u32;
274 events.push(RNodeEvent::Frequency(freq));
275 self.command = kiss::CMD_UNKNOWN;
276 self.in_frame = false;
277 }
278 }
279 CMD_BANDWIDTH => {
280 if buf.len() >= 4 {
281 let bw =
282 (buf[0] as u32) << 24 | (buf[1] as u32) << 16 | (buf[2] as u32) << 8 | buf[3] as u32;
283 events.push(RNodeEvent::Bandwidth(bw));
284 self.command = kiss::CMD_UNKNOWN;
285 self.in_frame = false;
286 }
287 }
288 CMD_TXPOWER => {
289 if buf.len() >= 1 {
290 events.push(RNodeEvent::TxPower(buf[0] as i8));
291 self.command = kiss::CMD_UNKNOWN;
292 self.in_frame = false;
293 }
294 }
295 CMD_SF => {
296 if buf.len() >= 1 {
297 events.push(RNodeEvent::SpreadingFactor(buf[0]));
298 self.command = kiss::CMD_UNKNOWN;
299 self.in_frame = false;
300 }
301 }
302 CMD_CR => {
303 if buf.len() >= 1 {
304 events.push(RNodeEvent::CodingRate(buf[0]));
305 self.command = kiss::CMD_UNKNOWN;
306 self.in_frame = false;
307 }
308 }
309 CMD_RADIO_STATE => {
310 if buf.len() >= 1 {
311 events.push(RNodeEvent::RadioState(buf[0]));
312 self.command = kiss::CMD_UNKNOWN;
313 self.in_frame = false;
314 }
315 }
316 CMD_STAT_RSSI => {
317 if buf.len() >= 1 {
318 events.push(RNodeEvent::StatRssi(buf[0]));
319 self.command = kiss::CMD_UNKNOWN;
320 self.in_frame = false;
321 }
322 }
323 CMD_STAT_SNR => {
324 if buf.len() >= 1 {
325 events.push(RNodeEvent::StatSnr(buf[0] as i8));
326 self.command = kiss::CMD_UNKNOWN;
327 self.in_frame = false;
328 }
329 }
330 CMD_ST_ALOCK => {
331 if buf.len() >= 2 {
332 let val = (buf[0] as u16) << 8 | buf[1] as u16;
333 events.push(RNodeEvent::StAlock(val));
334 self.command = kiss::CMD_UNKNOWN;
335 self.in_frame = false;
336 }
337 }
338 CMD_LT_ALOCK => {
339 if buf.len() >= 2 {
340 let val = (buf[0] as u16) << 8 | buf[1] as u16;
341 events.push(RNodeEvent::LtAlock(val));
342 self.command = kiss::CMD_UNKNOWN;
343 self.in_frame = false;
344 }
345 }
346 CMD_READY => {
347 events.push(RNodeEvent::Ready);
348 self.command = kiss::CMD_UNKNOWN;
349 self.in_frame = false;
350 }
351 CMD_SEL_INT => {
352 if buf.len() >= 1 {
353 self.selected_index = buf[0];
354 events.push(RNodeEvent::SelectedInterface(buf[0]));
355 self.command = kiss::CMD_UNKNOWN;
356 self.in_frame = false;
357 }
358 }
359 CMD_ERROR => {
360 if buf.len() >= 1 {
361 events.push(RNodeEvent::Error(buf[0]));
362 self.command = kiss::CMD_UNKNOWN;
363 self.in_frame = false;
364 }
365 }
366 _ => {
367 }
369 }
370 }
371}
372
373pub fn rnode_command(cmd: u8, value: &[u8]) -> Vec<u8> {
377 let escaped = kiss::escape(value);
378 let mut out = Vec::with_capacity(escaped.len() + 3);
379 out.push(kiss::FEND);
380 out.push(cmd);
381 out.extend_from_slice(&escaped);
382 out.push(kiss::FEND);
383 out
384}
385
386pub fn rnode_select_command(index: u8, cmd: u8, value: &[u8]) -> Vec<u8> {
389 let mut out = rnode_command(CMD_SEL_INT, &[index]);
390 out.extend_from_slice(&rnode_command(cmd, value));
391 out
392}
393
394pub fn detect_request() -> Vec<u8> {
396 rnode_command(CMD_DETECT, &[DETECT_REQ])
397}
398
399pub fn rnode_data_frame(index: u8, data: &[u8]) -> Vec<u8> {
402 let cmd = if (index as usize) < DATA_CMDS.len() {
403 DATA_CMDS[index as usize]
404 } else {
405 CMD_INT0_DATA
406 };
407 let escaped = kiss::escape(data);
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
416#[cfg(test)]
419mod tests {
420 use super::*;
421
422 #[test]
423 fn detect_request_format() {
424 let req = detect_request();
425 assert_eq!(req, vec![kiss::FEND, CMD_DETECT, DETECT_REQ, kiss::FEND]);
426 }
427
428 #[test]
429 fn decoder_detect_response() {
430 let response = vec![kiss::FEND, CMD_DETECT, DETECT_RESP, kiss::FEND];
431 let mut decoder = RNodeDecoder::new();
432 let events = decoder.feed(&response);
433 assert_eq!(events.len(), 1);
434 assert_eq!(events[0], RNodeEvent::Detected(true));
435 }
436
437 #[test]
438 fn decoder_firmware_version() {
439 let response = vec![kiss::FEND, CMD_FW_VERSION, 0x01, 0x34, kiss::FEND];
441 let mut decoder = RNodeDecoder::new();
442 let events = decoder.feed(&response);
443 assert_eq!(events.len(), 1);
444 assert_eq!(
445 events[0],
446 RNodeEvent::FirmwareVersion {
447 major: 1,
448 minor: 0x34
449 }
450 );
451 }
452
453 #[test]
454 fn decoder_platform() {
455 let response = vec![kiss::FEND, CMD_PLATFORM, 0x80, kiss::FEND]; let mut decoder = RNodeDecoder::new();
457 let events = decoder.feed(&response);
458 assert_eq!(events.len(), 1);
459 assert_eq!(events[0], RNodeEvent::Platform(0x80));
460 }
461
462 #[test]
463 fn decoder_interfaces() {
464 let response = vec![kiss::FEND, CMD_INTERFACES, 0x00, 0x01, kiss::FEND];
465 let mut decoder = RNodeDecoder::new();
466 let events = decoder.feed(&response);
467 assert_eq!(events.len(), 1);
468 assert_eq!(
469 events[0],
470 RNodeEvent::InterfaceType {
471 index: 0,
472 type_byte: 0x01
473 }
474 );
475 }
476
477 #[test]
478 fn decoder_frequency() {
479 let freq: u32 = 867_200_000;
482 let response = vec![
483 kiss::FEND,
484 CMD_FREQUENCY,
485 (freq >> 24) as u8,
486 (freq >> 16) as u8,
487 (freq >> 8) as u8,
488 (freq & 0xFF) as u8,
489 kiss::FEND,
490 ];
491 let mut decoder = RNodeDecoder::new();
492 let events = decoder.feed(&response);
493 assert_eq!(events.len(), 1);
494 assert_eq!(events[0], RNodeEvent::Frequency(867_200_000));
495 }
496
497 #[test]
498 fn decoder_data_frame_int0() {
499 let payload = vec![0x01, 0x02, 0x03, 0x04, 0x05];
500 let mut frame = vec![kiss::FEND, CMD_INT0_DATA];
502 frame.extend_from_slice(&kiss::escape(&payload));
503 frame.push(kiss::FEND);
504
505 let mut decoder = RNodeDecoder::new();
506 let events = decoder.feed(&frame);
507 assert_eq!(events.len(), 1);
508 assert_eq!(
509 events[0],
510 RNodeEvent::DataFrame {
511 index: 0,
512 data: payload
513 }
514 );
515 }
516
517 #[test]
518 fn decoder_multi_sub_data() {
519 let payload = vec![0xAA, 0xBB];
520 let mut frame = vec![kiss::FEND, CMD_INT1_DATA];
522 frame.extend_from_slice(&kiss::escape(&payload));
523 frame.push(kiss::FEND);
524
525 let mut decoder = RNodeDecoder::new();
526 let events = decoder.feed(&frame);
527 assert_eq!(events.len(), 1);
528 assert_eq!(
529 events[0],
530 RNodeEvent::DataFrame {
531 index: 1,
532 data: payload
533 }
534 );
535 }
536
537 #[test]
538 fn rnode_select_command_format() {
539 let freq: u32 = 868_000_000;
541 let freq_bytes = [
542 (freq >> 24) as u8,
543 (freq >> 16) as u8,
544 (freq >> 8) as u8,
545 (freq & 0xFF) as u8,
546 ];
547 let cmd = rnode_select_command(1, CMD_FREQUENCY, &freq_bytes);
548
549 assert_eq!(cmd[0], kiss::FEND);
551 assert_eq!(cmd[1], CMD_SEL_INT);
552 assert_eq!(cmd[2], 0x01);
553 assert_eq!(cmd[3], kiss::FEND);
554
555 assert_eq!(cmd[4], kiss::FEND);
557 assert_eq!(cmd[5], CMD_FREQUENCY);
558 }
559
560 #[test]
561 fn rnode_data_frame_format() {
562 let data = vec![0x01, 0x02, 0x03];
563 let frame = rnode_data_frame(0, &data);
564 assert_eq!(frame[0], kiss::FEND);
565 assert_eq!(frame[1], CMD_INT0_DATA);
566 assert_eq!(*frame.last().unwrap(), kiss::FEND);
567
568 let frame1 = rnode_data_frame(1, &data);
570 assert_eq!(frame1[1], CMD_INT1_DATA);
571
572 let frame2 = rnode_data_frame(2, &data);
574 assert_eq!(frame2[1], CMD_INT2_DATA);
575 }
576}