This commit is contained in:
Max Känner 2024-01-30 20:15:03 +01:00
parent d116ed9e26
commit eb5befa55c
3 changed files with 140 additions and 5 deletions

View File

@ -1,10 +1,13 @@
[package]
name = "lib-rs"
name = "crsf-rs"
version = "0.1.0"
edition = "2021"
description = "library template"
license_file = "MIT OR Apache-2.0"
description = "This crate provides a #[no_std] parser for the crossfire protocol"
license = "MIT OR Apache-2.0"
repository = "https://git.mkaenner.de/max/lib-rs"
keywords = ["crsf", "crossfire"]
categories = ["embedded"]
authors = ["Max Känner <max.kaenner@gmail.com>"]
[lints.rust]
unsafe_code = "forbid"
@ -19,3 +22,6 @@ cargo = "warn"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
num_enum = { version = "=0.5", default-features = false }
bitfield = { version = "=0.13" }
heapless = { version = "=0.7" }

View File

@ -1,3 +1,3 @@
# lib-rs
# crsf-rs
Template for rust libraries
A library for decoding crossfire packages. This library is fully #[no_std] compatible

View File

@ -1,2 +1,131 @@
#![cfg_attr(not(test), no_std)]
use bitfield::bitfield;
use heapless::HistoryBuffer;
use num_enum::{IntoPrimitive, TryFromPrimitive, TryFromPrimitiveError};
#[derive(Debug, PartialEq, Eq, Clone, Copy, IntoPrimitive, TryFromPrimitive)]
#[repr(u8)]
pub enum FrameType {
Gps = 0x02,
Vario = 0x07,
BatterySensor = 0x08,
BaroAltitude = 0x09,
LinkStatistics = 0x14,
OpenTxSync = 0x10,
RadioId = 0x3A,
RcChannelsPacked = 0x16,
Attitude = 0x1E,
FlightMode = 0x21,
// Extended Header Frames
DevicePing = 0x28,
DeviceInfo = 0x29,
ParameterSettingsEntry = 0x2B,
ParameterRead = 0x2C,
ParameterWrite = 0x2D,
ELRSStatus = 0x2E,
Command = 0x32,
// KISS frames
KissReq = 0x78,
KissResp = 0x79,
// MSP commands
MspReq = 0x7A,
MspResp = 0x7B,
MspWrite = 0x7C,
// Ardupilot frames
ArdupilotResp = 0x80,
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, IntoPrimitive, TryFromPrimitive)]
#[repr(u8)]
pub enum Address {
Broadcast = 0x00,
Usb = 0x10,
TbsCorePnpPro = 0x80,
Reserved1 = 0x8A,
CurrentSensor = 0xC0,
Gps = 0xC2,
TbsBlackbox = 0xC4,
FlightController = 0xC8,
Reserved2 = 0xCA,
RaceTag = 0xCC,
RadioTransmitter = 0xEA,
CrsfReceiver = 0xEC,
CrsfTrasmitter = 0xEE,
ElrsLua = 0xEF,
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
struct Header {
address: Address,
size: u8,
frame_type: FrameType,
}
impl Header {
fn try_from_bytes(bytes: [u8; 3]) -> Result<Self, u8> {
Ok(Self {
address: bytes[0]
.try_into()
.map_err(|TryFromPrimitiveError { number }| number)?,
size: bytes[1],
frame_type: bytes[2]
.try_into()
.map_err(|TryFromPrimitiveError { number }| number)?,
})
}
}
bitfield! {
struct RcChannels([u8]);
impl Debug;
u16;
ch1, set_ch1: Self::upper(1), Self::lower(1);
ch2, set_ch2: Self::upper(2), Self::lower(2);
ch3, set_ch3: Self::upper(3), Self::lower(3);
ch4, set_ch4: Self::upper(4), Self::lower(4);
ch5, set_ch5: Self::upper(5), Self::lower(5);
ch6, set_ch6: Self::upper(6), Self::lower(6);
ch7, set_ch7: Self::upper(7), Self::lower(7);
ch8, set_ch8: Self::upper(8), Self::lower(8);
ch9, set_ch9: Self::upper(9), Self::lower(9);
ch10, set_ch10: Self::upper(10), Self::lower(10);
ch11, set_ch11: Self::upper(11), Self::lower(11);
ch12, set_ch12: Self::upper(12), Self::lower(12);
ch13, set_ch13: Self::upper(13), Self::lower(13);
ch14, set_ch14: Self::upper(14), Self::lower(14);
ch15, set_ch15: Self::upper(15), Self::lower(15);
ch16, set_ch16: Self::upper(16), Self::lower(16);
}
impl<T> RcChannels<T> {
const BITS_PER_CHANNEL: usize = 11;
const fn upper(ch: usize) -> usize {
Self::lower(ch) + Self::BITS_PER_CHANNEL - 1
}
const fn lower(ch: usize) -> usize {
Self::BITS_PER_CHANNEL * (ch - 1)
}
}
pub struct CrsfParser {
buffer: HistoryBuffer<u8, { Self::MAX_PACKET_SIZE }>,
}
impl CrsfParser {
const MAX_PACKET_SIZE: usize = 64;
}
#[cfg(test)]
mod tests {
#[test]
fn rc_channels() {
let input = [
0xc8, 0x18, 0x16, 0xe0, 0x3, 0x1f, 0xb3, 0xc0, 0xf7, 0xb, 0xee, 0x69, 0x8f, 0x15, 0xe0,
0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x78, 0xd9, 0xdb, 0xb4, 0xc8,
];
unimplemented!();
}
}