mirror of
https://codeberg.org/icewind/hlk_ld6002.git
synced 2026-06-03 16:44:10 +02:00
embedded-io
This commit is contained in:
parent
83ea02403f
commit
64f3a6ad4c
4 changed files with 256 additions and 129 deletions
138
Cargo.lock
generated
138
Cargo.lock
generated
|
|
@ -11,36 +11,6 @@ dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "array-init"
|
|
||||||
version = "2.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "binrw"
|
|
||||||
version = "0.13.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "173901312e9850391d4d7c1318c4e099fdc037d61870fca427429830efdb4e5f"
|
|
||||||
dependencies = [
|
|
||||||
"array-init",
|
|
||||||
"binrw_derive",
|
|
||||||
"bytemuck",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "binrw_derive"
|
|
||||||
version = "0.13.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cb515fdd6f8d3a357c8e19b8ec59ef53880807864329b1cb1cba5c53bf76557e"
|
|
||||||
dependencies = [
|
|
||||||
"either",
|
|
||||||
"owo-colors",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 1.0.109",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
|
|
@ -70,7 +40,7 @@ checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.39",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -86,21 +56,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
|
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "embedded-io"
|
||||||
version = "1.9.0"
|
version = "0.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "equivalent"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.14.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hlk_ld6002"
|
name = "hlk_ld6002"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"binrw",
|
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
|
"embedded-io",
|
||||||
|
"num_enum",
|
||||||
"serialport",
|
"serialport",
|
||||||
"termion",
|
"termion",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "2.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177"
|
||||||
|
dependencies = [
|
||||||
|
"equivalent",
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "io-kit-sys"
|
name = "io-kit-sys"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
|
@ -174,24 +167,48 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_enum"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845"
|
||||||
|
dependencies = [
|
||||||
|
"num_enum_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_enum_derive"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-crate",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "numtoa"
|
name = "numtoa"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
|
checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "owo-colors"
|
|
||||||
version = "3.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pkg-config"
|
name = "pkg-config"
|
||||||
version = "0.3.27"
|
version = "0.3.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-crate"
|
||||||
|
version = "3.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284"
|
||||||
|
dependencies = [
|
||||||
|
"toml_edit",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.70"
|
version = "1.0.70"
|
||||||
|
|
@ -279,17 +296,6 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "syn"
|
|
||||||
version = "1.0.109"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.39"
|
version = "2.0.39"
|
||||||
|
|
@ -330,7 +336,24 @@ checksum = "268026685b2be38d7103e9e507c938a1fcb3d7e6eb15e87870b617bf37b6d581"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.39",
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_datetime"
|
||||||
|
version = "0.6.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_edit"
|
||||||
|
version = "0.21.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
|
"toml_datetime",
|
||||||
|
"winnow",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -369,3 +392,12 @@ name = "winapi-x86_64-pc-windows-gnu"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winnow"
|
||||||
|
version = "0.5.40"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,10 @@ description = "A library for interfacing with the HLK-LD6002 respiratory and hea
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bytemuck = { version = "1.14.3", features = ["derive"] }
|
bytemuck = { version = "1.14.3", features = ["derive"] }
|
||||||
binrw = { version = "0.13.3", default-features = false }
|
embedded-io = "0.6.1"
|
||||||
|
num_enum = { version = "0.7.2", default-features = false }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
binrw = { version = "0.13.3", features = ["std"] }
|
embedded-io = { version = "0.6.1", features = ["std"] }
|
||||||
serialport = "4.3.0"
|
serialport = "4.3.0"
|
||||||
termion = "3.0.0"
|
termion = "3.0.0"
|
||||||
|
|
@ -1,17 +1,18 @@
|
||||||
|
use embedded_io::{ErrorType, Read, ReadExactError};
|
||||||
|
use hlk_ld6002::{Data, MessageStream};
|
||||||
|
use serialport::ClearBuffer;
|
||||||
use std::env::args;
|
use std::env::args;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use serialport::ClearBuffer;
|
|
||||||
use hlk_ld6002::{Data, MessageStream};
|
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let port = args().nth(1).expect("no port provided");
|
let port = args().nth(1).expect("no port provided");
|
||||||
let port = serialport::new(&port, 1_382_400)
|
let port = serialport::new(&port, 1_382_400)
|
||||||
.timeout(Duration::from_millis(50))
|
.timeout(Duration::from_millis(50))
|
||||||
.open().expect("Failed to open port");
|
.open()
|
||||||
|
.expect("Failed to open port");
|
||||||
port.clear(ClearBuffer::All).expect("clear");
|
port.clear(ClearBuffer::All).expect("clear");
|
||||||
|
|
||||||
let mut messages = MessageStream::new(port);
|
let mut messages = MessageStream::new(ReadAdapter(port));
|
||||||
|
|
||||||
let mut data = Data::default();
|
let mut data = Data::default();
|
||||||
|
|
||||||
|
|
@ -21,11 +22,29 @@ fn main() {
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if let Some(message) = messages.next() {
|
if let Some(message) = messages.next() {
|
||||||
data.update(message);
|
if let Ok(message) = message {
|
||||||
if last.elapsed() > Duration::from_millis(100) {
|
data.update(message);
|
||||||
last = Instant::now();
|
if last.elapsed() > Duration::from_millis(100) {
|
||||||
print!("{:?}{}", data, termion::cursor::Restore);
|
last = Instant::now();
|
||||||
|
print!("{:?}{}", data, termion::cursor::Restore);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ReadAdapter<R>(R);
|
||||||
|
|
||||||
|
impl<R: std::io::Read> ErrorType for ReadAdapter<R> {
|
||||||
|
type Error = std::io::Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: std::io::Read> Read for ReadAdapter<R> {
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
||||||
|
self.0.read(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), ReadExactError<Self::Error>> {
|
||||||
|
self.0.read_exact(buf).map_err(ReadExactError::Other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
209
src/lib.rs
209
src/lib.rs
|
|
@ -1,23 +1,38 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
use binrw::error::Error as RwError;
|
|
||||||
use binrw::io::{NoSeek, Read, Seek};
|
|
||||||
use binrw::prelude::*;
|
|
||||||
use binrw::{Endian, VecArgs};
|
|
||||||
use bytemuck::{cast, cast_slice};
|
use bytemuck::{cast, cast_slice};
|
||||||
|
use embedded_io::{Error, Read, ReadExactError};
|
||||||
|
use num_enum::TryFromPrimitive;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum LdError<E> {
|
||||||
|
InvalidMessageType(u16),
|
||||||
InvalidDataLength {
|
InvalidDataLength {
|
||||||
expected: u16,
|
expected: u16,
|
||||||
got: u16,
|
got: u16,
|
||||||
ty: MessageType,
|
ty: MessageType,
|
||||||
},
|
},
|
||||||
|
InvalidChecksum {
|
||||||
|
ty: &'static str,
|
||||||
|
got: u8,
|
||||||
|
expected: u8,
|
||||||
|
},
|
||||||
|
InvalidFrameStart(u8),
|
||||||
|
Eof,
|
||||||
|
Read(E),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, BinRead, Copy)]
|
impl<E> From<ReadExactError<E>> for LdError<E> {
|
||||||
|
fn from(value: ReadExactError<E>) -> Self {
|
||||||
|
match value {
|
||||||
|
ReadExactError::UnexpectedEof => LdError::Eof,
|
||||||
|
ReadExactError::Other(e) => LdError::Read(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, TryFromPrimitive)]
|
||||||
#[repr(u16)]
|
#[repr(u16)]
|
||||||
#[brw(big, repr(u16))]
|
|
||||||
pub enum MessageType {
|
pub enum MessageType {
|
||||||
Phase = 0x0a13,
|
Phase = 0x0a13,
|
||||||
Respiratory = 0x0a14,
|
Respiratory = 0x0a14,
|
||||||
|
|
@ -25,6 +40,15 @@ pub enum MessageType {
|
||||||
Distance = 0x0a16,
|
Distance = 0x0a16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl MessageType {
|
||||||
|
pub fn read<R: Read>(mut reader: R) -> Result<Self, LdError<R::Error>> {
|
||||||
|
let mut bytes = [0u8; 2];
|
||||||
|
reader.read_exact(&mut bytes)?;
|
||||||
|
let ty = u16::from_be_bytes(bytes);
|
||||||
|
MessageType::try_from(ty).map_err(|e| LdError::InvalidMessageType(e.number))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl MessageType {
|
impl MessageType {
|
||||||
fn expected_length(self) -> u16 {
|
fn expected_length(self) -> u16 {
|
||||||
match self {
|
match self {
|
||||||
|
|
@ -36,68 +60,116 @@ impl MessageType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, BinRead)]
|
/// based on TinyFrame
|
||||||
#[brw(big)]
|
#[derive(Clone, Debug)]
|
||||||
#[allow(dead_code)]
|
struct FrameHeader {
|
||||||
struct Frame {
|
_id: u16,
|
||||||
id: u16,
|
|
||||||
#[br(assert(length <= 16))]
|
|
||||||
length: u16,
|
length: u16,
|
||||||
ty: MessageType,
|
ty: MessageType,
|
||||||
header_checksum: u8,
|
}
|
||||||
#[br(count = length)]
|
|
||||||
|
impl FrameHeader {
|
||||||
|
pub fn read<R: Read>(mut reader: R) -> Result<Self, LdError<R::Error>> {
|
||||||
|
let mut header_bytes = [0; 7];
|
||||||
|
reader.read_exact(&mut header_bytes)?;
|
||||||
|
|
||||||
|
let ty = u16::from_be_bytes([header_bytes[4], header_bytes[5]]);
|
||||||
|
let ty = MessageType::try_from(ty).map_err(|e| LdError::InvalidMessageType(e.number))?;
|
||||||
|
|
||||||
|
// let checksum = checksum(&header_bytes);
|
||||||
|
// if header_bytes[6] != checksum {
|
||||||
|
// return Err(LdError::InvalidChecksum {
|
||||||
|
// ty: "header",
|
||||||
|
// got: checksum,
|
||||||
|
// expected: header_bytes[6],
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
Ok(FrameHeader {
|
||||||
|
_id: u16::from_be_bytes([header_bytes[0], header_bytes[1]]),
|
||||||
|
length: u16::from_be_bytes([header_bytes[2], header_bytes[3]]),
|
||||||
|
ty,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
struct Frame {
|
||||||
|
header: FrameHeader,
|
||||||
data: FrameData<16>,
|
data: FrameData<16>,
|
||||||
data_checksum: u8,
|
}
|
||||||
|
|
||||||
|
impl Frame {
|
||||||
|
pub fn read<R: Read>(mut reader: R) -> Result<Self, LdError<R::Error>> {
|
||||||
|
let mut magic = [0];
|
||||||
|
reader.read_exact(&mut magic)?;
|
||||||
|
if magic[0] != 1 {
|
||||||
|
return Err(LdError::InvalidFrameStart(magic[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
let header = FrameHeader::read(&mut reader)?;
|
||||||
|
let data = FrameData::read(&mut reader, &header)?;
|
||||||
|
let mut data_checksum = [0];
|
||||||
|
reader.read_exact(&mut data_checksum)?;
|
||||||
|
let data_checksum = data_checksum[0];
|
||||||
|
|
||||||
|
let calculated_checksum = checksum(data.as_ref());
|
||||||
|
if data_checksum != calculated_checksum {
|
||||||
|
return Err(LdError::InvalidChecksum {
|
||||||
|
ty: "body",
|
||||||
|
got: calculated_checksum,
|
||||||
|
expected: data_checksum,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Frame { header, data })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct FrameData<const N: usize> {
|
struct FrameData<const N: usize> {
|
||||||
|
_align: u32,
|
||||||
data: [u8; N],
|
data: [u8; N],
|
||||||
len: usize,
|
len: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const N: usize> FrameData<N> {
|
impl<const N: usize> FrameData<N> {
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> u16 {
|
||||||
self.len
|
self.len
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read<R: Read>(mut reader: R, header: &FrameHeader) -> Result<Self, LdError<R::Error>> {
|
||||||
|
if header.length as usize > N || header.length != header.ty.expected_length() {
|
||||||
|
return Err(LdError::InvalidDataLength {
|
||||||
|
got: header.length,
|
||||||
|
expected: header.ty.expected_length(),
|
||||||
|
ty: header.ty,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut data = [0u8; N];
|
||||||
|
reader.read_exact(&mut data[0..header.length as usize])?;
|
||||||
|
|
||||||
|
Ok(FrameData {
|
||||||
|
_align: 0,
|
||||||
|
data,
|
||||||
|
len: header.length,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const N: usize> AsRef<[u8]> for FrameData<N> {
|
impl<const N: usize> AsRef<[u8]> for FrameData<N> {
|
||||||
fn as_ref(&self) -> &[u8] {
|
fn as_ref(&self) -> &[u8] {
|
||||||
&self.data[0..self.len]
|
&self.data[0..self.len as usize]
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<const N: usize> BinRead for FrameData<N> {
|
|
||||||
type Args<'a> = VecArgs<u8>;
|
|
||||||
|
|
||||||
fn read_options<R: Read + Seek>(
|
|
||||||
reader: &mut R,
|
|
||||||
_endian: Endian,
|
|
||||||
args: Self::Args<'_>,
|
|
||||||
) -> BinResult<Self> {
|
|
||||||
if args.count > N {
|
|
||||||
return Err(RwError::AssertFail {
|
|
||||||
pos: 0,
|
|
||||||
message: "".into(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let mut data = [0u8; N];
|
|
||||||
for byte in data.iter_mut().take(args.count) {
|
|
||||||
*byte = reader.read_be()?;
|
|
||||||
}
|
|
||||||
Ok(FrameData {
|
|
||||||
data,
|
|
||||||
len: args.count,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Frame {
|
impl Frame {
|
||||||
fn body(&self) -> Result<MessageBody, Error> {
|
fn body<E: Error>(&self) -> Result<MessageBody, LdError<E>> {
|
||||||
let numbers = cast_slice::<_, u32>(self.data.as_ref());
|
let numbers = cast_slice::<_, u32>(self.data.as_ref());
|
||||||
|
|
||||||
match (self.ty, self.data.len()) {
|
match (self.header.ty, self.data.len()) {
|
||||||
(MessageType::Phase, 12) => {
|
(MessageType::Phase, 12) => {
|
||||||
let numbers: [u32; 3] = numbers.try_into().unwrap();
|
let numbers: [u32; 3] = numbers.try_into().unwrap();
|
||||||
Ok(MessageBody::Phase(cast(numbers)))
|
Ok(MessageBody::Phase(cast(numbers)))
|
||||||
|
|
@ -115,10 +187,10 @@ impl Frame {
|
||||||
Ok(MessageBody::Distance(Some(distance)))
|
Ok(MessageBody::Distance(Some(distance)))
|
||||||
}
|
}
|
||||||
(MessageType::Distance, 4) => Ok(MessageBody::Distance(None)),
|
(MessageType::Distance, 4) => Ok(MessageBody::Distance(None)),
|
||||||
_ => Err(Error::InvalidDataLength {
|
_ => Err(LdError::InvalidDataLength {
|
||||||
got: self.data.len() as u16,
|
got: self.data.len(),
|
||||||
expected: self.ty.expected_length(),
|
expected: self.header.ty.expected_length(),
|
||||||
ty: self.ty,
|
ty: self.header.ty,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -133,34 +205,29 @@ pub enum MessageBody {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MessageStream<R> {
|
pub struct MessageStream<R> {
|
||||||
reader: NoSeek<R>,
|
reader: R,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Read> MessageStream<R> {
|
impl<R: Read> MessageStream<R> {
|
||||||
pub fn new(reader: R) -> Self {
|
pub fn new(reader: R) -> Self {
|
||||||
Self {
|
Self { reader }
|
||||||
reader: NoSeek::new(reader),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read(&mut self) -> Result<Frame, binrw::Error> {
|
fn read(&mut self) -> Result<Frame, LdError<R::Error>> {
|
||||||
let mut byte = [0];
|
Frame::read(&mut self.reader)
|
||||||
loop {
|
|
||||||
self.reader.read(&mut byte).ok();
|
|
||||||
if byte[0] == 0x01 {
|
|
||||||
return Frame::read(&mut self.reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Read> Iterator for MessageStream<R> {
|
impl<R: Read> Iterator for MessageStream<R> {
|
||||||
type Item = MessageBody;
|
type Item = Result<MessageBody, LdError<R::Error>>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
let frame = self.read().ok()?;
|
let frame = match self.read() {
|
||||||
|
Ok(frame) => frame,
|
||||||
|
Err(e) => return Some(Err(e)),
|
||||||
|
};
|
||||||
|
|
||||||
frame.body().ok()
|
Some(frame.body::<R::Error>())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -174,16 +241,24 @@ pub struct Data {
|
||||||
impl Data {
|
impl Data {
|
||||||
pub fn update(&mut self, message: MessageBody) {
|
pub fn update(&mut self, message: MessageBody) {
|
||||||
match message {
|
match message {
|
||||||
MessageBody::Respiratory(rate) => {
|
MessageBody::Respiratory(rate) if rate > 0.0 => {
|
||||||
self.respiratory = rate;
|
self.respiratory = rate;
|
||||||
}
|
}
|
||||||
MessageBody::Distance(Some(distance)) if distance > 0.0 => {
|
MessageBody::Distance(Some(distance)) if distance > 0.0 => {
|
||||||
self.distance = distance;
|
self.distance = distance;
|
||||||
}
|
}
|
||||||
MessageBody::Heartbeat(rate) => {
|
MessageBody::Heartbeat(rate) if rate > 0.0 => {
|
||||||
self.heartbeat = rate;
|
self.heartbeat = rate;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn checksum(data: &[u8]) -> u8 {
|
||||||
|
let mut result = 0;
|
||||||
|
for byte in data {
|
||||||
|
result ^= byte;
|
||||||
|
}
|
||||||
|
!result
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue