A start
This commit is contained in:
parent
d116ed9e26
commit
eb5befa55c
12
Cargo.toml
12
Cargo.toml
@ -1,10 +1,13 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "lib-rs"
|
name = "crsf-rs"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "library template"
|
description = "This crate provides a #[no_std] parser for the crossfire protocol"
|
||||||
license_file = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
repository = "https://git.mkaenner.de/max/lib-rs"
|
repository = "https://git.mkaenner.de/max/lib-rs"
|
||||||
|
keywords = ["crsf", "crossfire"]
|
||||||
|
categories = ["embedded"]
|
||||||
|
authors = ["Max Känner <max.kaenner@gmail.com>"]
|
||||||
|
|
||||||
[lints.rust]
|
[lints.rust]
|
||||||
unsafe_code = "forbid"
|
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
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
num_enum = { version = "=0.5", default-features = false }
|
||||||
|
bitfield = { version = "=0.13" }
|
||||||
|
heapless = { version = "=0.7" }
|
||||||
|
@ -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
|
||||||
|
129
src/lib.rs
129
src/lib.rs
@ -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!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user