1#![no_std]
35use crc::{Crc, CRC_8_DVB_S2};
38#[cfg(feature = "defmt")]
39use defmt;
40use snafu::prelude::*;
41
42use buffer::CircularBuffer;
43
44pub use packets::*;
45
46mod buffer;
47mod packets;
48
49pub const MAX_PACKET_LENGTH: usize = 64;
51pub const PACKET_HEADER_LENGTH: usize = 2;
53
54pub struct PacketParser<const C: usize> {
56 buf: CircularBuffer<C>,
57}
58
59impl<const C: usize> PacketParser<C> {
60 const MIN_DATA_LENGTH: u8 = 2;
62 const MAX_DATA_LENGTH: u8 = MAX_PACKET_LENGTH as u8 - Self::MIN_DATA_LENGTH;
64
65 pub const fn new() -> Self {
67 Self {
68 buf: CircularBuffer::new(),
69 }
70 }
71
72 pub fn clear(&mut self) {
74 self.buf.clear();
75 }
76
77 pub fn push_bytes(&mut self, bytes: &[u8]) {
79 bytes.iter().for_each(|&val| {
80 self.buf.push_back(val);
81 });
82 }
83
84 pub fn next_raw_packet(&mut self) -> Option<Result<RawPacket, PacketError>> {
86 self.sync();
87
88 if self.buf.len() < PACKET_HEADER_LENGTH {
89 return None;
90 }
91
92 let len_byte = self.buf.peek_front(1).unwrap();
93 if !(Self::MIN_DATA_LENGTH..=Self::MAX_DATA_LENGTH).contains(&len_byte) {
94 for _ in 0..PACKET_HEADER_LENGTH {
95 self.buf.pop_front();
96 }
97 return Some(Err(PacketError::InvalidLength { len: len_byte }));
98 }
99 let len = PACKET_HEADER_LENGTH + len_byte as usize;
100
101 if len > self.buf.len() {
102 return None;
103 }
104
105 let mut data: [u8; MAX_PACKET_LENGTH] = [0; MAX_PACKET_LENGTH];
106 for c in data.iter_mut() {
107 *c = self.buf.pop_front().unwrap_or(0);
108 }
109
110 Some(Ok(RawPacket { data, len }))
111 }
112
113 pub fn next_packet(&mut self) -> Option<Result<(PacketAddress, Packet), PacketError>> {
115 self.next_raw_packet().map(|raw_packet| match raw_packet {
116 Ok(raw_packet) => {
117 let destination = PacketAddress::from_u8(raw_packet.data[0]).unwrap();
118 let packet = Packet::from_raw(&raw_packet)?;
119 Ok((destination, packet))
120 }
121 Err(err) => Err(err),
122 })
123 }
124
125 fn sync(&mut self) {
126 while self
127 .buf
128 .peek_front(0)
129 .is_some_and(|val| PacketAddress::from_u8(val).is_none())
130 {
131 self.buf.pop_front();
132 }
133 }
134}
135
136#[non_exhaustive]
138#[derive(Clone, Debug)]
139pub enum Packet {
140 LinkStatistics(LinkStatistics),
141 RcChannels(RcChannels),
142}
143
144impl Packet {
145 pub fn from_raw(raw_packet: &RawPacket) -> Result<Self, PacketError> {
147 let data = raw_packet.data();
148
149 let checksum_idx = data.len() - 1;
150 let checksum = Self::calculate_checksum(&data[2..checksum_idx]);
151 if checksum != data[checksum_idx] {
152 return Err(PacketError::ChecksumMismatch {
153 expected: checksum,
154 actual: data[checksum_idx],
155 });
156 }
157
158 let raw_type = data[2];
159 let payload_data = &data[3..];
160 let packet = match PacketType::from_u8(raw_type) {
161 Some(PacketType::RcChannelsPacked) => {
162 Packet::RcChannels(RcChannels::parse(payload_data))
163 }
164 Some(PacketType::LinkStatistics) => {
165 Packet::LinkStatistics(LinkStatistics::parse(payload_data))
166 }
167 _ => return Err(PacketError::UnknownType { raw_type }),
168 };
169 Ok(packet)
170 }
171
172 pub fn into_raw(&self, addr: PacketAddress) -> RawPacket {
174 let mut data: [u8; MAX_PACKET_LENGTH] = [0; MAX_PACKET_LENGTH];
175
176 data[0] = addr as u8;
177
178 let payload = match self {
179 Packet::LinkStatistics(payload) => payload as &dyn Payload,
180 Packet::RcChannels(payload) => payload as &dyn Payload,
181 };
182
183 let len_byte = payload.len() + 2;
184 let len = PACKET_HEADER_LENGTH + len_byte as usize;
185 data[1] = len_byte;
186
187 data[2] = payload.packet_type() as u8;
188
189 payload.dump(&mut data[3..]);
190
191 let checksum_idx = len - 1;
192 data[checksum_idx] = Self::calculate_checksum(&data[2..checksum_idx]);
193
194 RawPacket { data, len }
195 }
196
197 fn calculate_checksum(data: &[u8]) -> u8 {
198 let crc8_alg = Crc::<u8>::new(&CRC_8_DVB_S2);
199 crc8_alg.checksum(data)
200 }
201}
202
203#[derive(Clone, Debug)]
205pub struct RawPacket {
206 data: [u8; MAX_PACKET_LENGTH],
207 len: usize,
208}
209
210impl RawPacket {
211 pub fn data(&self) -> &[u8] {
213 &self.data[..self.len]
214 }
215}
216
217#[non_exhaustive]
219#[derive(Debug, PartialEq, Snafu)]
220#[cfg_attr(feature = "defmt", derive(defmt::Format))]
221pub enum PacketError {
222 #[snafu(display("Invalid length: {len}"))]
223 InvalidLength { len: u8 },
224 #[snafu(display("Unknown type: {raw_type:#04x}"))]
225 UnknownType { raw_type: u8 },
226 #[snafu(display("Checksum mismatch: expected {expected:#04x} but was {actual:#04x}"))]
227 ChecksumMismatch { expected: u8, actual: u8 },
228}
229
230#[non_exhaustive]
232#[derive(Debug, Clone, Copy, PartialEq, Eq)]
233#[repr(u8)]
234pub enum PacketAddress {
235 Transmitter = 0xEE,
236 Handset = 0xEA,
237 Controller = 0xC8,
238 Receiver = 0xEC,
239}
240
241impl PacketAddress {
242 pub fn from_u8(val: u8) -> Option<Self> {
243 match val {
244 0xEE => Some(PacketAddress::Transmitter),
245 0xEA => Some(PacketAddress::Handset),
246 0xC8 => Some(PacketAddress::Controller),
247 0xEC => Some(PacketAddress::Receiver),
248 _ => None,
249 }
250 }
251}
252
253#[non_exhaustive]
255#[derive(Debug, Clone, Copy, PartialEq, Eq)]
256#[repr(u8)]
257pub enum PacketType {
258 Gps = 0x02,
259 Vario = 0x07,
260 BatterySensor = 0x08,
261 BaroAltitude = 0x09,
262 LinkStatistics = 0x14,
263 OpenTxSync = 0x10,
264 RadioId = 0x3A,
265 RcChannelsPacked = 0x16,
266 Altitude = 0x1E,
267 FlightMode = 0x21,
268 DevicePing = 0x28,
269 DeviceInfo = 0x29,
270 ParameterSettingsEntry = 0x2B,
271 ParameterRead = 0x2C,
272 ParameterWrite = 0x2D,
273 Command = 0x32,
274 KissRequest = 0x78,
275 KissResponse = 0x79,
276 MspRequest = 0x7A,
277 MspResponse = 0x7B,
278 MspWrite = 0x7C,
279 ArdupilotResponse = 0x80,
280}
281
282impl PacketType {
283 pub fn from_u8(val: u8) -> Option<Self> {
284 match val {
285 0x02 => Some(PacketType::Gps),
286 0x07 => Some(PacketType::Vario),
287 0x08 => Some(PacketType::BatterySensor),
288 0x09 => Some(PacketType::BaroAltitude),
289 0x14 => Some(PacketType::LinkStatistics),
290 0x10 => Some(PacketType::OpenTxSync),
291 0x3A => Some(PacketType::RadioId),
292 0x16 => Some(PacketType::RcChannelsPacked),
293 0x1E => Some(PacketType::Altitude),
294 0x21 => Some(PacketType::FlightMode),
295 0x28 => Some(PacketType::DevicePing),
296 0x29 => Some(PacketType::DeviceInfo),
297 0x2B => Some(PacketType::ParameterSettingsEntry),
298 0x2C => Some(PacketType::ParameterRead),
299 0x2D => Some(PacketType::ParameterWrite),
300 0x32 => Some(PacketType::Command),
301 0x78 => Some(PacketType::KissRequest),
302 0x79 => Some(PacketType::KissResponse),
303 0x7A => Some(PacketType::MspRequest),
304 0x7B => Some(PacketType::MspResponse),
305 0x7C => Some(PacketType::MspWrite),
306 0x80 => Some(PacketType::ArdupilotResponse),
307 _ => None,
308 }
309 }
310}
311
312#[cfg(test)]
313mod tests {
314 use crate::LinkStatistics;
315 use crate::Packet;
316 use crate::PacketAddress;
317
318 use super::PacketError;
319 use super::PacketParser;
320 use super::PacketType;
321 use super::RcChannels;
322
323 #[test]
324 fn test_parse_next_packet() {
325 let mut parser = PacketParser::<1024>::new();
326
327 let addr = PacketAddress::Controller;
328 let typ = PacketType::RcChannelsPacked;
329
330 parser.push_bytes(&[addr as u8]);
332 assert!(matches!(parser.next_packet(), None));
333 parser.push_bytes(&[24]);
335 assert!(matches!(parser.next_packet(), None));
336 parser.push_bytes(&[typ as u8]);
338 assert!(matches!(parser.next_packet(), None));
339 parser.push_bytes(&[0; 22]);
341 assert!(matches!(parser.next_packet(), None));
342 parser.push_bytes(&[239]);
344
345 match parser.next_packet() {
346 None => panic!("Packet expected"),
347 Some(Ok((_, packet))) => {
348 if let Packet::RcChannels(RcChannels(channels)) = packet {
349 assert_eq!(channels, [0; 16]);
350 } else {
351 panic!("Packet was supposed to be of type rc channels");
352 }
353 }
354 Some(Err(e)) => panic!("Packet expected instead of an error: {}", e),
355 }
356 assert!(matches!(parser.next_packet(), None));
357 }
358
359 #[test]
360 fn test_parse_next_packet_with_validation_error() {
361 let mut parser = PacketParser::<1024>::new();
362
363 let addr = PacketAddress::Controller;
364
365 parser.push_bytes(&[addr as u8]);
367 assert!(matches!(parser.next_packet(), None));
368 parser.push_bytes(&[24]);
370 assert!(matches!(parser.next_packet(), None));
371 parser.push_bytes(&[PacketType::RcChannelsPacked as u8]);
373 assert!(matches!(parser.next_packet(), None));
374 parser.push_bytes(&[0; 22]);
376 assert!(matches!(parser.next_packet(), None));
377 parser.push_bytes(&[42]);
379
380 match parser.next_packet() {
381 None | Some(Ok(_)) => panic!("Validation error expected"),
382 Some(Err(e)) => {
383 assert_eq!(
384 e,
385 PacketError::ChecksumMismatch {
386 expected: 239,
387 actual: 42
388 }
389 )
390 }
391 }
392 assert!(matches!(parser.next_packet(), None));
393 }
394
395 #[test]
396 fn test_parse_next_packet_with_zero_len() {
397 let mut parser = PacketParser::<1024>::new();
398
399 let addr = PacketAddress::Controller;
400
401 parser.push_bytes(&[addr as u8]);
403 assert!(matches!(parser.next_packet(), None));
404 parser.push_bytes(&[0]);
406 match parser.next_packet() {
407 None | Some(Ok(_)) => panic!("Validation error expected"),
408 Some(Err(e)) => {
409 assert_eq!(e, PacketError::InvalidLength { len: 0 })
410 }
411 }
412 assert!(matches!(parser.next_packet(), None));
413 }
414
415 #[test]
416 fn test_parse_next_packet_with_max_len() {
417 let mut parser = PacketParser::<1024>::new();
418
419 let addr = PacketAddress::Controller;
420
421 parser.push_bytes(&[addr as u8]);
423 assert!(matches!(parser.next_packet(), None));
424 parser.push_bytes(&[62]);
426 parser.push_bytes(&[0xff]);
428 parser.push_bytes(&[0; 60]);
430 parser.push_bytes(&[33]);
432 match parser.next_packet() {
433 None | Some(Ok(_)) => panic!("Validation error expected"),
434 Some(Err(e)) => {
435 assert_eq!(e, PacketError::UnknownType { raw_type: 0xff })
436 }
437 }
438 assert!(matches!(parser.next_packet(), None));
439 }
440
441 #[test]
442 fn test_parse_next_packet_with_too_big_len() {
443 let mut parser = PacketParser::<1024>::new();
444
445 parser.push_bytes(&[0xc8]);
447 assert!(matches!(parser.next_packet(), None));
448 parser.push_bytes(&[63]);
450 match parser.next_packet() {
451 None | Some(Ok(_)) => panic!("Validation error expected"),
452 Some(Err(e)) => {
453 assert_eq!(e, PacketError::InvalidLength { len: 63 })
454 }
455 }
456 assert!(matches!(parser.next_packet(), None));
457 }
458
459 #[test]
460 fn test_packet_construction() {
461 let addr = PacketAddress::Controller;
462
463 let channels: [u16; 16] = [0; 16];
464 let packet = Packet::RcChannels(RcChannels(channels));
465
466 let raw_packet = packet.into_raw(addr);
467
468 let packet2 = Packet::from_raw(&raw_packet).unwrap();
469 if let Packet::RcChannels(RcChannels(channels2)) = packet2 {
470 assert_eq!(channels, channels2);
471 }
472 }
473
474 #[test]
475 fn test_rc_channels_packet_into_raw() {
476 let channels: [u16; 16] = [0xffff; 16];
477 let packet = Packet::RcChannels(RcChannels(channels));
478
479 let raw_packet = packet.into_raw(PacketAddress::Transmitter);
480 let mut expected_data: [u8; 26] = [0xff; 26];
481 expected_data[0] = 0xee;
482 expected_data[1] = 24;
483 expected_data[2] = 0x16;
484 expected_data[25] = 143;
485 assert_eq!(raw_packet.data(), &expected_data)
486 }
487
488 #[test]
489 fn test_link_statistics_packet_into_raw() {
490 let packet = Packet::LinkStatistics(LinkStatistics {
491 uplink_rssi_1: 16,
492 uplink_rssi_2: 19,
493 uplink_link_quality: 99,
494 uplink_snr: -105,
495 active_antenna: 1,
496 rf_mode: 2,
497 uplink_tx_power: 3,
498 downlink_rssi: 8,
499 downlink_link_quality: 88,
500 downlink_snr: -108,
501 });
502
503 let raw_packet = packet.into_raw(PacketAddress::Controller);
504 let expected_data = [0xc8, 12, 0x14, 16, 19, 99, 151, 1, 2, 3, 8, 88, 148, 252];
505 assert_eq!(raw_packet.data(), &expected_data)
506 }
507}