#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(clippy::unwrap_used)]
use tinyklv::prelude::*; use tinyklv::dec::binary as decb; use tinyklv::enc::binary as encb;
const NAV_SENTINEL: &[u8] = b"NAVFRAME";
const WX_SENTINEL: &[u8] = b"WXFRAME";
#[derive(Klv, Debug, PartialEq)]
#[klv(
stream = &[u8],
sentinel = b"NAVFRAME",
key(dec = decb::u8, enc = encb::u8),
len(dec = decb::u8_as_usize, enc = encb::u8_from_usize),
)]
struct NavFrame {
#[klv(
key = 0x01,
dec = decb::be_f32,
enc = *encb::be_f32,
)]
lat_deg: f32,
#[klv(
key = 0x02,
dec = decb::be_f32,
enc = *encb::be_f32,
)]
lon_deg: f32,
#[klv(
key = 0x03,
dec = decb::be_u16,
enc = *encb::be_u16,
)]
heading_centideg: u16,
}
#[derive(Klv, Debug, PartialEq)]
#[klv(
stream = &[u8],
sentinel = b"WXFRAME",
key(dec = decb::u8, enc = encb::u8),
len(dec = decb::u8_as_usize, enc = encb::u8_from_usize),
)]
struct WeatherFrame {
#[klv(
key = 0x01,
dec = decb::be_u16,
enc = *encb::be_u16,
)]
pressure_hpa: u16,
#[klv(
key = 0x02,
dec = decb::u8,
enc = *encb::u8,
)]
humidity_pct: u8,
}
#[derive(Debug, PartialEq)]
enum TelemetryPacket {
Nav(NavFrame),
Weather(WeatherFrame),
}
fn dispatch_one(input: &mut &[u8]) -> Option<TelemetryPacket> {
if input.starts_with(NAV_SENTINEL) {
return NavFrame::decode_frame(input).ok().map(TelemetryPacket::Nav);
}
if input.starts_with(WX_SENTINEL) {
return WeatherFrame::decode_frame(input).ok().map(TelemetryPacket::Weather);
}
if input.is_empty() {
return None;
}
*input = &input[1..];
None
}
fn main() {
let nav1 = NavFrame { lat_deg: 51.5, lon_deg: -0.1, heading_centideg: 27_000 };
let wx1 = WeatherFrame { pressure_hpa: 1013, humidity_pct: 65 };
let nav2 = NavFrame { lat_deg: 51.6, lon_deg: -0.2, heading_centideg: 9_000 };
let wx2 = WeatherFrame { pressure_hpa: 1011, humidity_pct: 72 };
let mut stream: Vec<u8> = Vec::new();
stream.extend(nav1.encode_frame());
stream.extend_from_slice(&[
0xDE, 0xAD, 0xFF,
]);
stream.extend(wx1.encode_frame());
stream.extend(nav2.encode_frame());
stream.extend(wx2.encode_frame());
let mut slice = stream.as_slice();
let mut packets: Vec<TelemetryPacket> = Vec::new();
while !slice.is_empty() {
if let Some(p) = dispatch_one(&mut slice) {
packets.push(p);
}
}
assert_eq!(packets.len(), 4);
assert_eq!(packets[0], TelemetryPacket::Nav(nav1));
assert_eq!(packets[1], TelemetryPacket::Weather(wx1));
assert_eq!(packets[2], TelemetryPacket::Nav(nav2));
assert_eq!(packets[3], TelemetryPacket::Weather(wx2));
}