Decode rc channel packet
This commit is contained in:
parent
be930d313b
commit
22d19bc092
79
src/lib.rs
79
src/lib.rs
@ -1,8 +1,8 @@
|
|||||||
#![cfg_attr(not(test), no_std)]
|
// #![cfg_attr(not(test), no_std)]
|
||||||
|
|
||||||
use bitfield::bitfield;
|
use bitfield::bitfield;
|
||||||
use crc::{Crc, CRC_8_DVB_S2};
|
use crc::{Crc, CRC_8_DVB_S2};
|
||||||
use heapless::Deque;
|
use heapless::{Deque, Vec};
|
||||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, IntoPrimitive, TryFromPrimitive)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy, IntoPrimitive, TryFromPrimitive)]
|
||||||
@ -37,6 +37,48 @@ pub enum FrameType {
|
|||||||
ArdupilotResp = 0x80,
|
ArdupilotResp = 0x80,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub enum CrsfPacket {
|
||||||
|
RcChannels([u16; 16]),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CrsfPacket {
|
||||||
|
fn from_type_and_data(
|
||||||
|
frame_type: FrameType,
|
||||||
|
data: impl Iterator<Item = u8> + ExactSizeIterator,
|
||||||
|
) -> Option<Self> {
|
||||||
|
match frame_type {
|
||||||
|
FrameType::RcChannelsPacked => {
|
||||||
|
if data.len() != 22 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let mut buf = Vec::<u8, 22>::new();
|
||||||
|
buf.extend(data);
|
||||||
|
let channels = RcChannelsPacked(&mut buf[..]);
|
||||||
|
Some(Self::RcChannels([
|
||||||
|
channels.ch1(),
|
||||||
|
channels.ch2(),
|
||||||
|
channels.ch3(),
|
||||||
|
channels.ch4(),
|
||||||
|
channels.ch5(),
|
||||||
|
channels.ch6(),
|
||||||
|
channels.ch7(),
|
||||||
|
channels.ch8(),
|
||||||
|
channels.ch9(),
|
||||||
|
channels.ch10(),
|
||||||
|
channels.ch11(),
|
||||||
|
channels.ch12(),
|
||||||
|
channels.ch13(),
|
||||||
|
channels.ch14(),
|
||||||
|
channels.ch15(),
|
||||||
|
channels.ch16(),
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, IntoPrimitive, TryFromPrimitive)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy, IntoPrimitive, TryFromPrimitive)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum Address {
|
pub enum Address {
|
||||||
@ -63,6 +105,15 @@ pub struct Header {
|
|||||||
frame_type: FrameType,
|
frame_type: FrameType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Header {
|
||||||
|
const fn valid(self) -> bool {
|
||||||
|
match self.frame_type {
|
||||||
|
FrameType::RcChannelsPacked => self.size == 24,
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bitfield! {
|
bitfield! {
|
||||||
struct RcChannelsPacked([u8]);
|
struct RcChannelsPacked([u8]);
|
||||||
impl Debug;
|
impl Debug;
|
||||||
@ -118,7 +169,7 @@ impl CrsfParser {
|
|||||||
let _ = self.buffer.push_front(byte);
|
let _ = self.buffer.push_front(byte);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next_packet(&mut self) -> Option<Header> {
|
pub fn next_packet(&mut self) -> Option<(Address, CrsfPacket)> {
|
||||||
const CRC8_ALG: Crc<u8> = Crc::<u8>::new(&CRC_8_DVB_S2);
|
const CRC8_ALG: Crc<u8> = Crc::<u8>::new(&CRC_8_DVB_S2);
|
||||||
|
|
||||||
while Address::try_from(*self.buffer.back()?).is_err() {
|
while Address::try_from(*self.buffer.back()?).is_err() {
|
||||||
@ -141,6 +192,10 @@ impl CrsfParser {
|
|||||||
frame_type,
|
frame_type,
|
||||||
};
|
};
|
||||||
// TODO: check the frame size against the frame type.
|
// TODO: check the frame size against the frame type.
|
||||||
|
if !header.valid() {
|
||||||
|
self.buffer.pop_back();
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
// The size field contains the number of bytes coming after it.
|
// The size field contains the number of bytes coming after it.
|
||||||
let packet_length = header.size + 2;
|
let packet_length = header.size + 2;
|
||||||
@ -164,19 +219,20 @@ impl CrsfParser {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: decode payload using type field
|
// decode payload using type field
|
||||||
|
let packet = CrsfPacket::from_type_and_data(header.frame_type, payload_iter);
|
||||||
|
|
||||||
// sucessfully decoded a packet
|
// sucessfully decoded a packet
|
||||||
for _ in 0..packet_length {
|
for _ in 0..packet_length {
|
||||||
self.buffer.pop_back()?;
|
self.buffer.pop_back()?;
|
||||||
}
|
}
|
||||||
Some(header)
|
packet.map(|packet| (header.address, packet))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{Address, CrsfParser, FrameType, Header};
|
use crate::{Address, CrsfPacket, CrsfParser};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rc_channels() {
|
fn rc_channels() {
|
||||||
@ -193,11 +249,12 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parser.next_packet(),
|
parser.next_packet(),
|
||||||
Some(Header {
|
Some((
|
||||||
address: Address::FlightController,
|
Address::FlightController,
|
||||||
size: 24,
|
CrsfPacket::RcChannels([
|
||||||
frame_type: FrameType::RcChannelsPacked
|
992, 992, 716, 992, 191, 988, 986, 172, 992, 0, 0, 0, 0, 0, 1630, 1758
|
||||||
})
|
])
|
||||||
|
))
|
||||||
);
|
);
|
||||||
assert_eq!(parser.next_packet(), None);
|
assert_eq!(parser.next_packet(), None);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user