Compare commits
No commits in common. "55d0dace03fe9c8f5aaa250560e89586ebdd83e7" and "bccf6456c52dd9f3e19e5d5f0823627217207c84" have entirely different histories.
55d0dace03
...
bccf6456c5
7 changed files with 176 additions and 365 deletions
48
firmware/Cargo.lock
generated
48
firmware/Cargo.lock
generated
|
|
@ -74,9 +74,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.9.1"
|
version = "2.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
|
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block-device-driver"
|
name = "block-device-driver"
|
||||||
|
|
@ -245,7 +245,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-embedded-hal"
|
name = "embassy-embedded-hal"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/embassy-rs/embassy#e8b1ea14c7fb151aa5e296ca8f9724f175bdeaef"
|
source = "git+https://github.com/embassy-rs/embassy#eb68a81c2ab2d90abd036f3597a1a242c5e8702b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"defmt 0.3.100",
|
"defmt 0.3.100",
|
||||||
"embassy-futures",
|
"embassy-futures",
|
||||||
|
|
@ -263,7 +263,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-executor"
|
name = "embassy-executor"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
source = "git+https://github.com/embassy-rs/embassy#e8b1ea14c7fb151aa5e296ca8f9724f175bdeaef"
|
source = "git+https://github.com/embassy-rs/embassy#eb68a81c2ab2d90abd036f3597a1a242c5e8702b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cortex-m",
|
"cortex-m",
|
||||||
"critical-section",
|
"critical-section",
|
||||||
|
|
@ -275,7 +275,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-executor-macros"
|
name = "embassy-executor-macros"
|
||||||
version = "0.6.2"
|
version = "0.6.2"
|
||||||
source = "git+https://github.com/embassy-rs/embassy#e8b1ea14c7fb151aa5e296ca8f9724f175bdeaef"
|
source = "git+https://github.com/embassy-rs/embassy#eb68a81c2ab2d90abd036f3597a1a242c5e8702b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling",
|
"darling",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
|
@ -286,7 +286,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-futures"
|
name = "embassy-futures"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
source = "git+https://github.com/embassy-rs/embassy#e8b1ea14c7fb151aa5e296ca8f9724f175bdeaef"
|
source = "git+https://github.com/embassy-rs/embassy#eb68a81c2ab2d90abd036f3597a1a242c5e8702b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"defmt 0.3.100",
|
"defmt 0.3.100",
|
||||||
]
|
]
|
||||||
|
|
@ -294,7 +294,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-hal-internal"
|
name = "embassy-hal-internal"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/embassy-rs/embassy#e8b1ea14c7fb151aa5e296ca8f9724f175bdeaef"
|
source = "git+https://github.com/embassy-rs/embassy#eb68a81c2ab2d90abd036f3597a1a242c5e8702b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cortex-m",
|
"cortex-m",
|
||||||
"critical-section",
|
"critical-section",
|
||||||
|
|
@ -305,7 +305,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-net-driver"
|
name = "embassy-net-driver"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/embassy-rs/embassy#e8b1ea14c7fb151aa5e296ca8f9724f175bdeaef"
|
source = "git+https://github.com/embassy-rs/embassy#eb68a81c2ab2d90abd036f3597a1a242c5e8702b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"defmt 0.3.100",
|
"defmt 0.3.100",
|
||||||
]
|
]
|
||||||
|
|
@ -313,11 +313,11 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-stm32"
|
name = "embassy-stm32"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/embassy-rs/embassy#e8b1ea14c7fb151aa5e296ca8f9724f175bdeaef"
|
source = "git+https://github.com/embassy-rs/embassy#eb68a81c2ab2d90abd036f3597a1a242c5e8702b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aligned",
|
"aligned",
|
||||||
"bit_field",
|
"bit_field",
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.0",
|
||||||
"block-device-driver",
|
"block-device-driver",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cortex-m",
|
"cortex-m",
|
||||||
|
|
@ -360,7 +360,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-sync"
|
name = "embassy-sync"
|
||||||
version = "0.6.2"
|
version = "0.6.2"
|
||||||
source = "git+https://github.com/embassy-rs/embassy#e8b1ea14c7fb151aa5e296ca8f9724f175bdeaef"
|
source = "git+https://github.com/embassy-rs/embassy#eb68a81c2ab2d90abd036f3597a1a242c5e8702b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"critical-section",
|
"critical-section",
|
||||||
|
|
@ -374,7 +374,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-time"
|
name = "embassy-time"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "git+https://github.com/embassy-rs/embassy#e8b1ea14c7fb151aa5e296ca8f9724f175bdeaef"
|
source = "git+https://github.com/embassy-rs/embassy#eb68a81c2ab2d90abd036f3597a1a242c5e8702b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"critical-section",
|
"critical-section",
|
||||||
|
|
@ -390,7 +390,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-time-driver"
|
name = "embassy-time-driver"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/embassy-rs/embassy#e8b1ea14c7fb151aa5e296ca8f9724f175bdeaef"
|
source = "git+https://github.com/embassy-rs/embassy#eb68a81c2ab2d90abd036f3597a1a242c5e8702b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"document-features",
|
"document-features",
|
||||||
]
|
]
|
||||||
|
|
@ -398,7 +398,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-time-queue-utils"
|
name = "embassy-time-queue-utils"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/embassy-rs/embassy#e8b1ea14c7fb151aa5e296ca8f9724f175bdeaef"
|
source = "git+https://github.com/embassy-rs/embassy#eb68a81c2ab2d90abd036f3597a1a242c5e8702b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"embassy-executor",
|
"embassy-executor",
|
||||||
"heapless",
|
"heapless",
|
||||||
|
|
@ -407,7 +407,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-usb-driver"
|
name = "embassy-usb-driver"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/embassy-rs/embassy#e8b1ea14c7fb151aa5e296ca8f9724f175bdeaef"
|
source = "git+https://github.com/embassy-rs/embassy#eb68a81c2ab2d90abd036f3597a1a242c5e8702b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"defmt 0.3.100",
|
"defmt 0.3.100",
|
||||||
"embedded-io-async",
|
"embedded-io-async",
|
||||||
|
|
@ -416,7 +416,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-usb-synopsys-otg"
|
name = "embassy-usb-synopsys-otg"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/embassy-rs/embassy#e8b1ea14c7fb151aa5e296ca8f9724f175bdeaef"
|
source = "git+https://github.com/embassy-rs/embassy#eb68a81c2ab2d90abd036f3597a1a242c5e8702b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"critical-section",
|
"critical-section",
|
||||||
"defmt 0.3.100",
|
"defmt 0.3.100",
|
||||||
|
|
@ -516,9 +516,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.3.12"
|
version = "0.3.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
|
checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
|
|
@ -635,9 +635,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "micropb"
|
name = "micropb"
|
||||||
version = "0.1.2"
|
version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bff8c16c9fb4b03e9b23e0bc17ce3b67465c3f0f75a004a65d604d382c13b7bd"
|
checksum = "3fba9d45f70365e5ecfe23bc1dbe523ce5c3f2e81aa762880961b61ab25c99a7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heapless",
|
"heapless",
|
||||||
"never",
|
"never",
|
||||||
|
|
@ -646,9 +646,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "micropb-gen"
|
name = "micropb-gen"
|
||||||
version = "0.1.2"
|
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 = "dd8b5b73c6511641cc191a1c7ba95cbe86abb9801dcb6f2a6d8d23b79836ee31"
|
checksum = "21d0a9d827869dd3d834e6992c6a8fdb4229a82b44afe0679e82efe14c50643e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"convert_case",
|
"convert_case",
|
||||||
"micropb",
|
"micropb",
|
||||||
|
|
@ -862,7 +862,7 @@ version = "1.0.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
|
checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.0",
|
||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys",
|
"linux-raw-sys",
|
||||||
|
|
@ -1100,5 +1100,5 @@ version = "0.39.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
|
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.0",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -20,13 +20,13 @@ embedded-resources = { version = "0.2.1", features = ["stm32"] }
|
||||||
portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] }
|
portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] }
|
||||||
static_cell = "2.1.0"
|
static_cell = "2.1.0"
|
||||||
|
|
||||||
thiserror = { version = "2.0.12", default-features = false }
|
|
||||||
micropb = { version = "0.1.1", default-features = false, features = [ "encode", "decode", "container-heapless" ] }
|
micropb = { version = "0.1.1", default-features = false, features = [ "encode", "decode", "container-heapless" ] }
|
||||||
|
|
||||||
defmt = { version = "1.0.0", optional = true }
|
defmt = { version = "1.0.0", optional = true }
|
||||||
defmt-rtt = { version = "1.0.0", optional = true }
|
defmt-rtt = { version = "1.0.0", optional = true }
|
||||||
panic-probe = { version = "1.0.0", optional = true }
|
panic-probe = { version = "1.0.0", optional = true }
|
||||||
panic-halt = "1.0.0"
|
panic-halt = "1.0.0"
|
||||||
|
thiserror = { version = "2.0.12", default-features = false }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
micropb-gen = "0.1.0"
|
micropb-gen = "0.1.0"
|
||||||
|
|
@ -35,7 +35,7 @@ micropb-gen = "0.1.0"
|
||||||
default = ["board-nucleo64", "status-led", "trace"]
|
default = ["board-nucleo64", "status-led", "trace"]
|
||||||
board-nucleo64 = []
|
board-nucleo64 = []
|
||||||
status-led = []
|
status-led = []
|
||||||
copy-within = []
|
use-copy-within = []
|
||||||
trace = [
|
trace = [
|
||||||
"dep:defmt",
|
"dep:defmt",
|
||||||
"dep:defmt-rtt",
|
"dep:defmt-rtt",
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ extern crate core;
|
||||||
|
|
||||||
mod crc_engine;
|
mod crc_engine;
|
||||||
mod tasks;
|
mod tasks;
|
||||||
mod uart;
|
mod uarts;
|
||||||
|
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
use crate::{crc_engine, println, uart};
|
use crate::uarts::{UartReadError, read_frame_fragment};
|
||||||
|
use crate::{crc_engine, println};
|
||||||
use byteorder::{ByteOrder, LittleEndian};
|
use byteorder::{ByteOrder, LittleEndian};
|
||||||
use core::str::FromStr;
|
use core::str::FromStr;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_stm32::{gpio, usart};
|
use embassy_stm32::{gpio, usart};
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use embedded_io_async::Write;
|
use embedded_io_async::{Read, Write};
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
|
|
||||||
use micropb::{
|
use micropb::{
|
||||||
|
|
@ -131,67 +132,104 @@ async fn tx_task(mut tx: Tx, crc: crc_engine::CrcHandle) {
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
#[allow(clippy::too_many_lines)]
|
#[allow(clippy::too_many_lines)]
|
||||||
async fn rx_task(rx: Rx, crc: crc_engine::CrcHandle) {
|
async fn rx_task(mut rx: Rx, crc: crc_engine::CrcHandle) {
|
||||||
let mut frx = uart::framed_rx::FramedUartRx::new(
|
|
||||||
rx.message_buf,
|
|
||||||
rx.uart,
|
|
||||||
SYNC_BYTE,
|
|
||||||
Duration::from_millis(250),
|
|
||||||
Duration::from_millis(50),
|
|
||||||
);
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
frx.wait_for_frame_sync().await;
|
// look for a sync byte in the buffer; the buffer may have
|
||||||
|
// leftover bytes from a previous cycle through this loop
|
||||||
|
// (due to an incomplete message, or a message which failed
|
||||||
|
// validation)
|
||||||
|
if let Some(sync) = rx.message_buf.iter().position(|&x| x == SYNC_BYTE) {
|
||||||
|
// if a sync byte was found, reset the buffer to the data
|
||||||
|
// following it
|
||||||
|
//
|
||||||
|
let post_bytes = rx.message_buf.len() - sync - 1;
|
||||||
|
#[cfg(not(feature = "use-copy-within"))]
|
||||||
|
for i in 0..post_bytes {
|
||||||
|
rx.message_buf[i] = rx.message_buf[sync + 1 + i];
|
||||||
|
}
|
||||||
|
#[cfg(feature = "use-copy-within")]
|
||||||
|
rx.message_buf.copy_within(sync + 1.., 0);
|
||||||
|
rx.message_buf.truncate(post_bytes);
|
||||||
|
} else {
|
||||||
|
// wait for a sync byte to arrive
|
||||||
|
let mut buf = [0_u8; 1];
|
||||||
|
loop {
|
||||||
|
if (rx.uart.read_exact(&mut buf).await).is_ok() && buf[0] == SYNC_BYTE {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
println!("received sync byte from host");
|
println!("received sync byte from host");
|
||||||
|
|
||||||
// sync byte was seen, read the length of the message; if
|
// sync byte was seen, read the length of the message; if
|
||||||
// there aren't enough bytes in the buffer, wait for them,
|
// there aren't enough bytes in the buffer, wait for them,
|
||||||
// with timeouts
|
// with timeouts
|
||||||
match frx.read_frame_fragment(0, MESSAGE_LENGTH_SIZE).await {
|
match read_frame_fragment(
|
||||||
|
rx.message_buf,
|
||||||
|
0,
|
||||||
|
MESSAGE_LENGTH_SIZE,
|
||||||
|
&mut rx.uart,
|
||||||
|
Duration::from_millis(250),
|
||||||
|
Duration::from_millis(50),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(uart::ReadError::ReadyCheck) => {
|
Err(UartReadError::Ready) => {
|
||||||
println!("uart ready-check error reading message length");
|
println!("uart ready error reading message length");
|
||||||
frx.buf.clear();
|
rx.message_buf.clear();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Err(uart::ReadError::BufferCapacity) => {
|
Err(UartReadError::BufferCapacity) => {
|
||||||
println!("insufficient space to read message length");
|
println!("insufficient space to read message length");
|
||||||
frx.buf.clear();
|
rx.message_buf.clear();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Err(uart::ReadError::Timeout) => {
|
Err(UartReadError::Timeout) => {
|
||||||
// restart loop, since the sync byte seen wasn't
|
// restart loop, since the sync byte seen wasn't
|
||||||
// the beginning of a message, or the sender
|
// the beginning of a message, or the sender
|
||||||
// stopped sending
|
// stopped sending
|
||||||
println!("timeout waiting for message length");
|
println!("timeout waiting for message message length");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the message length from the buffer
|
// get the message length from the buffer
|
||||||
let message_len = LittleEndian::read_u16(&frx.buf[..MESSAGE_LENGTH_SIZE]) as usize;
|
let message_len = LittleEndian::read_u16(&rx.message_buf[..MESSAGE_LENGTH_SIZE]) as usize;
|
||||||
|
|
||||||
println!("receiving message of {=u16} bytes", message_len as u16);
|
println!("receiving message of {=u16} bytes", message_len as u16);
|
||||||
|
|
||||||
// read the message; if there aren't enough bytes in the
|
// read the message; if there aren't enough bytes in the
|
||||||
// buffer for the message, wait for them, with timeouts
|
// buffer for the message, wait for them to arrive, with
|
||||||
|
// timeouts
|
||||||
let message_pos = MESSAGE_LENGTH_SIZE;
|
let message_pos = MESSAGE_LENGTH_SIZE;
|
||||||
match frx.read_frame_fragment(message_pos, message_len).await {
|
match read_frame_fragment(
|
||||||
|
rx.message_buf,
|
||||||
|
message_pos,
|
||||||
|
message_len,
|
||||||
|
&mut rx.uart,
|
||||||
|
Duration::from_millis(250),
|
||||||
|
Duration::from_millis(50),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(uart::ReadError::ReadyCheck) => {
|
Err(UartReadError::Ready) => {
|
||||||
println!("uart ready-check error reading message body");
|
println!("uart ready error reading message");
|
||||||
frx.buf.clear();
|
rx.message_buf.clear();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Err(uart::ReadError::BufferCapacity) => {
|
Err(UartReadError::BufferCapacity) => {
|
||||||
println!("insufficient space to read message body");
|
println!("insufficient space to read message");
|
||||||
frx.buf.clear();
|
rx.message_buf.clear();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Err(uart::ReadError::Timeout) => {
|
Err(UartReadError::Timeout) => {
|
||||||
// restart loop, since the sync byte seen wasn't
|
// restart loop, since the sync byte seen wasn't
|
||||||
// the beginning of a message, or the sender
|
// the beginning of a message, or the sender
|
||||||
// stopped sending
|
// stopped sending
|
||||||
println!("timeout waiting for message body");
|
println!("timeout waiting for message message");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -199,19 +237,28 @@ async fn rx_task(rx: Rx, crc: crc_engine::CrcHandle) {
|
||||||
// read the CRC-16 of the message; if there aren't enough
|
// read the CRC-16 of the message; if there aren't enough
|
||||||
// bytes in the buffer, wait for them, with timeouts
|
// bytes in the buffer, wait for them, with timeouts
|
||||||
let crc_pos = message_pos + message_len;
|
let crc_pos = message_pos + message_len;
|
||||||
match frx.read_frame_fragment(crc_pos, MESSAGE_CRC_SIZE).await {
|
match read_frame_fragment(
|
||||||
|
rx.message_buf,
|
||||||
|
crc_pos,
|
||||||
|
MESSAGE_CRC_SIZE,
|
||||||
|
&mut rx.uart,
|
||||||
|
Duration::from_millis(250),
|
||||||
|
Duration::from_millis(50),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(uart::ReadError::ReadyCheck) => {
|
Err(UartReadError::Ready) => {
|
||||||
println!("uart ready-check error reading CRC-16");
|
println!("uart ready error reading CRC-16");
|
||||||
frx.buf.clear();
|
rx.message_buf.clear();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Err(uart::ReadError::BufferCapacity) => {
|
Err(UartReadError::BufferCapacity) => {
|
||||||
println!("insufficient space to read CRC-16");
|
println!("insufficient space to read CRC-16");
|
||||||
frx.buf.clear();
|
rx.message_buf.clear();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Err(uart::ReadError::Timeout) => {
|
Err(UartReadError::Timeout) => {
|
||||||
// restart loop, since the sync byte seen wasn't
|
// restart loop, since the sync byte seen wasn't
|
||||||
// the beginning of a message, or the sender
|
// the beginning of a message, or the sender
|
||||||
// stopped sending
|
// stopped sending
|
||||||
|
|
@ -221,9 +268,9 @@ async fn rx_task(rx: Rx, crc: crc_engine::CrcHandle) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the expected CRC-16 from the buffer
|
// get the expected CRC-16 from the buffer
|
||||||
let expected_crc = LittleEndian::read_u16(&frx.buf[crc_pos..MESSAGE_CRC_SIZE]);
|
let expected_crc = LittleEndian::read_u16(&rx.message_buf[crc_pos..MESSAGE_CRC_SIZE]);
|
||||||
// compute the actual CRC-16
|
// compute the actual CRC-16
|
||||||
let computed_crc = crc.compute(&frx.buf[message_pos..message_len]).await;
|
let computed_crc = crc.compute(&rx.message_buf[message_pos..message_len]).await;
|
||||||
|
|
||||||
if computed_crc != expected_crc {
|
if computed_crc != expected_crc {
|
||||||
println!(
|
println!(
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
pub mod echo_ {
|
pub mod echo_ {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct EchoRequest {
|
pub struct EchoRequest {
|
||||||
pub r#data: u32,
|
pub r#data: u32,
|
||||||
}
|
}
|
||||||
|
|
@ -10,37 +10,7 @@ pub mod echo_ {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl ::core::cmp::PartialEq for EchoRequest {
|
impl EchoRequest {}
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
let mut ret = true;
|
|
||||||
ret &= (self.r#data == other.r#data);
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl EchoRequest {
|
|
||||||
///Return a reference to `data`
|
|
||||||
#[inline]
|
|
||||||
pub fn r#data(&self) -> &u32 {
|
|
||||||
&self.r#data
|
|
||||||
}
|
|
||||||
///Return a mutable reference to `data`
|
|
||||||
#[inline]
|
|
||||||
pub fn mut_data(&mut self) -> &mut u32 {
|
|
||||||
&mut self.r#data
|
|
||||||
}
|
|
||||||
///Set the value of `data`
|
|
||||||
#[inline]
|
|
||||||
pub fn set_data(&mut self, value: u32) -> &mut Self {
|
|
||||||
self.r#data = value.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
///Builder method that sets the value of `data`. Useful for initializing the message.
|
|
||||||
#[inline]
|
|
||||||
pub fn init_data(mut self, value: u32) -> Self {
|
|
||||||
self.r#data = value.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl ::micropb::MessageDecode for EchoRequest {
|
impl ::micropb::MessageDecode for EchoRequest {
|
||||||
fn decode<IMPL_MICROPB_READ: ::micropb::PbRead>(
|
fn decode<IMPL_MICROPB_READ: ::micropb::PbRead>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
@ -98,7 +68,7 @@ pub mod echo_ {
|
||||||
size
|
size
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct EchoResponse {
|
pub struct EchoResponse {
|
||||||
pub r#data: u32,
|
pub r#data: u32,
|
||||||
}
|
}
|
||||||
|
|
@ -109,37 +79,7 @@ pub mod echo_ {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl ::core::cmp::PartialEq for EchoResponse {
|
impl EchoResponse {}
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
let mut ret = true;
|
|
||||||
ret &= (self.r#data == other.r#data);
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl EchoResponse {
|
|
||||||
///Return a reference to `data`
|
|
||||||
#[inline]
|
|
||||||
pub fn r#data(&self) -> &u32 {
|
|
||||||
&self.r#data
|
|
||||||
}
|
|
||||||
///Return a mutable reference to `data`
|
|
||||||
#[inline]
|
|
||||||
pub fn mut_data(&mut self) -> &mut u32 {
|
|
||||||
&mut self.r#data
|
|
||||||
}
|
|
||||||
///Set the value of `data`
|
|
||||||
#[inline]
|
|
||||||
pub fn set_data(&mut self, value: u32) -> &mut Self {
|
|
||||||
self.r#data = value.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
///Builder method that sets the value of `data`. Useful for initializing the message.
|
|
||||||
#[inline]
|
|
||||||
pub fn init_data(mut self, value: u32) -> Self {
|
|
||||||
self.r#data = value.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl ::micropb::MessageDecode for EchoResponse {
|
impl ::micropb::MessageDecode for EchoResponse {
|
||||||
fn decode<IMPL_MICROPB_READ: ::micropb::PbRead>(
|
fn decode<IMPL_MICROPB_READ: ::micropb::PbRead>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
@ -199,7 +139,7 @@ pub mod echo_ {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub mod test_ {
|
pub mod test_ {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct TestResponse {
|
pub struct TestResponse {
|
||||||
pub r#f1: u32,
|
pub r#f1: u32,
|
||||||
pub r#f2: ::micropb::heapless::String<16>,
|
pub r#f2: ::micropb::heapless::String<16>,
|
||||||
|
|
@ -216,106 +156,7 @@ pub mod test_ {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl ::core::cmp::PartialEq for TestResponse {
|
impl TestResponse {}
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
let mut ret = true;
|
|
||||||
ret &= (self.r#f1 == other.r#f1);
|
|
||||||
ret &= (self.r#f2 == other.r#f2);
|
|
||||||
ret &= (self.r#f3 == other.r#f3);
|
|
||||||
ret &= (self.r#f4 == other.r#f4);
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl TestResponse {
|
|
||||||
///Return a reference to `f1`
|
|
||||||
#[inline]
|
|
||||||
pub fn r#f1(&self) -> &u32 {
|
|
||||||
&self.r#f1
|
|
||||||
}
|
|
||||||
///Return a mutable reference to `f1`
|
|
||||||
#[inline]
|
|
||||||
pub fn mut_f1(&mut self) -> &mut u32 {
|
|
||||||
&mut self.r#f1
|
|
||||||
}
|
|
||||||
///Set the value of `f1`
|
|
||||||
#[inline]
|
|
||||||
pub fn set_f1(&mut self, value: u32) -> &mut Self {
|
|
||||||
self.r#f1 = value.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
///Builder method that sets the value of `f1`. Useful for initializing the message.
|
|
||||||
#[inline]
|
|
||||||
pub fn init_f1(mut self, value: u32) -> Self {
|
|
||||||
self.r#f1 = value.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
///Return a reference to `f2`
|
|
||||||
#[inline]
|
|
||||||
pub fn r#f2(&self) -> &::micropb::heapless::String<16> {
|
|
||||||
&self.r#f2
|
|
||||||
}
|
|
||||||
///Return a mutable reference to `f2`
|
|
||||||
#[inline]
|
|
||||||
pub fn mut_f2(&mut self) -> &mut ::micropb::heapless::String<16> {
|
|
||||||
&mut self.r#f2
|
|
||||||
}
|
|
||||||
///Set the value of `f2`
|
|
||||||
#[inline]
|
|
||||||
pub fn set_f2(&mut self, value: ::micropb::heapless::String<16>) -> &mut Self {
|
|
||||||
self.r#f2 = value.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
///Builder method that sets the value of `f2`. Useful for initializing the message.
|
|
||||||
#[inline]
|
|
||||||
pub fn init_f2(mut self, value: ::micropb::heapless::String<16>) -> Self {
|
|
||||||
self.r#f2 = value.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
///Return a reference to `f3`
|
|
||||||
#[inline]
|
|
||||||
pub fn r#f3(&self) -> &bool {
|
|
||||||
&self.r#f3
|
|
||||||
}
|
|
||||||
///Return a mutable reference to `f3`
|
|
||||||
#[inline]
|
|
||||||
pub fn mut_f3(&mut self) -> &mut bool {
|
|
||||||
&mut self.r#f3
|
|
||||||
}
|
|
||||||
///Set the value of `f3`
|
|
||||||
#[inline]
|
|
||||||
pub fn set_f3(&mut self, value: bool) -> &mut Self {
|
|
||||||
self.r#f3 = value.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
///Builder method that sets the value of `f3`. Useful for initializing the message.
|
|
||||||
#[inline]
|
|
||||||
pub fn init_f3(mut self, value: bool) -> Self {
|
|
||||||
self.r#f3 = value.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
///Return a reference to `f4`
|
|
||||||
#[inline]
|
|
||||||
pub fn r#f4(&self) -> &::micropb::heapless::Vec<u8, 8> {
|
|
||||||
&self.r#f4
|
|
||||||
}
|
|
||||||
///Return a mutable reference to `f4`
|
|
||||||
#[inline]
|
|
||||||
pub fn mut_f4(&mut self) -> &mut ::micropb::heapless::Vec<u8, 8> {
|
|
||||||
&mut self.r#f4
|
|
||||||
}
|
|
||||||
///Set the value of `f4`
|
|
||||||
#[inline]
|
|
||||||
pub fn set_f4(&mut self, value: ::micropb::heapless::Vec<u8, 8>) -> &mut Self {
|
|
||||||
self.r#f4 = value.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
///Builder method that sets the value of `f4`. Useful for initializing the message.
|
|
||||||
#[inline]
|
|
||||||
pub fn init_f4(mut self, value: ::micropb::heapless::Vec<u8, 8>) -> Self {
|
|
||||||
self.r#f4 = value.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl ::micropb::MessageDecode for TestResponse {
|
impl ::micropb::MessageDecode for TestResponse {
|
||||||
fn decode<IMPL_MICROPB_READ: ::micropb::PbRead>(
|
fn decode<IMPL_MICROPB_READ: ::micropb::PbRead>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
@ -445,7 +286,7 @@ pub mod api_ {
|
||||||
Resp(super::Response),
|
Resp(super::Response),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Message {
|
pub struct Message {
|
||||||
pub r#inner: ::core::option::Option<Message_::Inner>,
|
pub r#inner: ::core::option::Option<Message_::Inner>,
|
||||||
}
|
}
|
||||||
|
|
@ -456,13 +297,6 @@ pub mod api_ {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl ::core::cmp::PartialEq for Message {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
let mut ret = true;
|
|
||||||
ret &= (self.r#inner == other.r#inner);
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Message {}
|
impl Message {}
|
||||||
impl ::micropb::MessageDecode for Message {
|
impl ::micropb::MessageDecode for Message {
|
||||||
fn decode<IMPL_MICROPB_READ: ::micropb::PbRead>(
|
fn decode<IMPL_MICROPB_READ: ::micropb::PbRead>(
|
||||||
|
|
@ -568,7 +402,7 @@ pub mod api_ {
|
||||||
Echo(super::super::echo_::EchoRequest),
|
Echo(super::super::echo_::EchoRequest),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Request {
|
pub struct Request {
|
||||||
pub r#msg: ::core::option::Option<Request_::Msg>,
|
pub r#msg: ::core::option::Option<Request_::Msg>,
|
||||||
}
|
}
|
||||||
|
|
@ -579,13 +413,6 @@ pub mod api_ {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl ::core::cmp::PartialEq for Request {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
let mut ret = true;
|
|
||||||
ret &= (self.r#msg == other.r#msg);
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Request {}
|
impl Request {}
|
||||||
impl ::micropb::MessageDecode for Request {
|
impl ::micropb::MessageDecode for Request {
|
||||||
fn decode<IMPL_MICROPB_READ: ::micropb::PbRead>(
|
fn decode<IMPL_MICROPB_READ: ::micropb::PbRead>(
|
||||||
|
|
@ -664,7 +491,7 @@ pub mod api_ {
|
||||||
Test(super::super::test_::TestResponse),
|
Test(super::super::test_::TestResponse),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Response {
|
pub struct Response {
|
||||||
pub r#msg: ::core::option::Option<Response_::Msg>,
|
pub r#msg: ::core::option::Option<Response_::Msg>,
|
||||||
}
|
}
|
||||||
|
|
@ -675,13 +502,6 @@ pub mod api_ {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl ::core::cmp::PartialEq for Response {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
let mut ret = true;
|
|
||||||
ret &= (self.r#msg == other.r#msg);
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Response {}
|
impl Response {}
|
||||||
impl ::micropb::MessageDecode for Response {
|
impl ::micropb::MessageDecode for Response {
|
||||||
fn decode<IMPL_MICROPB_READ: ::micropb::PbRead>(
|
fn decode<IMPL_MICROPB_READ: ::micropb::PbRead>(
|
||||||
|
|
|
||||||
|
|
@ -1,100 +0,0 @@
|
||||||
use crate::uart;
|
|
||||||
use embassy_stm32::usart;
|
|
||||||
use embassy_time::Duration;
|
|
||||||
use embedded_io_async::Read;
|
|
||||||
use micropb::heapless::Vec;
|
|
||||||
|
|
||||||
pub struct FramedUartRx<const N: usize> {
|
|
||||||
pub buf: &'static mut Vec<u8, N>,
|
|
||||||
uart: usart::BufferedUartRx<'static>,
|
|
||||||
sync: u8,
|
|
||||||
first_byte_timeout: Duration,
|
|
||||||
between_bytes_timeout: Duration,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<const N: usize> FramedUartRx<N> {
|
|
||||||
pub fn new(
|
|
||||||
buf: &'static mut Vec<u8, N>,
|
|
||||||
uart: usart::BufferedUartRx<'static>,
|
|
||||||
sync: u8,
|
|
||||||
first_byte_timeout: Duration,
|
|
||||||
between_bytes_timeout: Duration,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
buf,
|
|
||||||
uart,
|
|
||||||
sync,
|
|
||||||
first_byte_timeout,
|
|
||||||
between_bytes_timeout,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn wait_for_frame_sync(&mut self) {
|
|
||||||
// look for a sync byte in the buffer; the buffer may have
|
|
||||||
// leftover bytes from a previous cycle (due to an incomplete
|
|
||||||
// message, or a message which failed validation)
|
|
||||||
if let Some(sync_pos) = self.buf.iter().position(|&x| x == self.sync) {
|
|
||||||
// if a sync byte was found, reset the buffer to the data
|
|
||||||
// following it
|
|
||||||
//
|
|
||||||
let post_bytes = self.buf.len() - sync_pos - 1;
|
|
||||||
#[cfg(not(feature = "copy-within"))]
|
|
||||||
for i in 0..post_bytes {
|
|
||||||
self.buf[i] = self.buf[sync_pos + 1 + i];
|
|
||||||
}
|
|
||||||
#[cfg(feature = "copy-within")]
|
|
||||||
self.buf.copy_within(sync_pos + 1.., 0);
|
|
||||||
self.buf.truncate(post_bytes);
|
|
||||||
} else {
|
|
||||||
// wait for a sync byte to arrive
|
|
||||||
let mut buf = [0_u8; 1];
|
|
||||||
loop {
|
|
||||||
if (self.uart.read_exact(&mut buf).await).is_ok() && buf[0] == self.sync {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn read_frame_fragment(
|
|
||||||
&mut self,
|
|
||||||
fragment_pos: usize,
|
|
||||||
fragment_len: usize,
|
|
||||||
) -> Result<(), uart::ReadError> {
|
|
||||||
// compute the number of bytes available in the buffer, and the
|
|
||||||
// number of bytes to read
|
|
||||||
let bytes_available = self.buf[fragment_pos..].len();
|
|
||||||
let bytes_to_read = fragment_len.saturating_sub(bytes_available);
|
|
||||||
if bytes_to_read == 0 {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the fragment will not fit in the buffer's available space,
|
|
||||||
// return an error
|
|
||||||
if bytes_to_read > (self.buf.capacity() - self.buf.len()) {
|
|
||||||
return Err(uart::ReadError::BufferCapacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if there aren't enough bytes in the buffer for the
|
|
||||||
// fragment, wait for them to arrive, with a timeout
|
|
||||||
if let Ok(r) = uart::read_with_timeouts(
|
|
||||||
&mut self.uart,
|
|
||||||
&mut self.buf[fragment_pos + bytes_available..bytes_to_read],
|
|
||||||
self.first_byte_timeout,
|
|
||||||
self.between_bytes_timeout,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
unsafe {
|
|
||||||
self.buf.set_len(fragment_pos + bytes_available + r);
|
|
||||||
}
|
|
||||||
if r < bytes_to_read {
|
|
||||||
return Err(uart::ReadError::Timeout);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(uart::ReadError::Timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -2,16 +2,15 @@ use embassy_stm32::usart;
|
||||||
use embassy_time::{Duration, WithTimeout};
|
use embassy_time::{Duration, WithTimeout};
|
||||||
use embedded_io::ReadReady;
|
use embedded_io::ReadReady;
|
||||||
use embedded_io_async::Read;
|
use embedded_io_async::Read;
|
||||||
|
use micropb::heapless::Vec;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
pub mod framed_rx;
|
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum ReadError {
|
pub enum UartReadError {
|
||||||
#[error("timeout expired waiting for data")]
|
#[error("timeout expired waiting for data")]
|
||||||
Timeout,
|
Timeout,
|
||||||
#[error("ready check on uart failed")]
|
#[error("ready check on uart failed")]
|
||||||
ReadyCheck,
|
Ready,
|
||||||
#[error("buffer is too small for message fragment")]
|
#[error("buffer is too small for message fragment")]
|
||||||
BufferCapacity,
|
BufferCapacity,
|
||||||
}
|
}
|
||||||
|
|
@ -24,10 +23,10 @@ pub enum ReadError {
|
||||||
/// `between_bytes`: if data is available immediately, or after the
|
/// `between_bytes`: if data is available immediately, or after the
|
||||||
/// first byte has been read, will wait this long between bytes
|
/// first byte has been read, will wait this long between bytes
|
||||||
///
|
///
|
||||||
/// Returns `ReadError::ReadyCheck` if the initial check for data returns an
|
/// Returns `UartReadError::Ready` if the initial check for data returns an
|
||||||
/// error
|
/// error
|
||||||
///
|
///
|
||||||
/// Returns `ReadError::Timeout` if the first-byte timeout expires
|
/// Returns `UartReadError::Timeout` if the first-byte timeout expires
|
||||||
///
|
///
|
||||||
/// Returns `Ok()` with the number of bytes read in all other cases,
|
/// Returns `Ok()` with the number of bytes read in all other cases,
|
||||||
/// including a between-bytes timeout; in that case the data read
|
/// including a between-bytes timeout; in that case the data read
|
||||||
|
|
@ -37,7 +36,7 @@ async fn read_with_timeouts(
|
||||||
buf: &mut [u8],
|
buf: &mut [u8],
|
||||||
first_byte: Duration,
|
first_byte: Duration,
|
||||||
between_bytes: Duration,
|
between_bytes: Duration,
|
||||||
) -> Result<usize, ReadError> {
|
) -> Result<usize, UartReadError> {
|
||||||
// if the requested read size is zero bytes, return immediately
|
// if the requested read size is zero bytes, return immediately
|
||||||
if buf.is_empty() {
|
if buf.is_empty() {
|
||||||
return Ok(0);
|
return Ok(0);
|
||||||
|
|
@ -48,7 +47,7 @@ async fn read_with_timeouts(
|
||||||
if let Ok(ready) = rx.read_ready() {
|
if let Ok(ready) = rx.read_ready() {
|
||||||
timeout = if ready { between_bytes } else { first_byte };
|
timeout = if ready { between_bytes } else { first_byte };
|
||||||
} else {
|
} else {
|
||||||
return Err(ReadError::ReadyCheck);
|
return Err(UartReadError::Ready);
|
||||||
}
|
}
|
||||||
|
|
||||||
while bytes_read < buf.len() {
|
while bytes_read < buf.len() {
|
||||||
|
|
@ -59,9 +58,54 @@ async fn read_with_timeouts(
|
||||||
if bytes_read > 0 {
|
if bytes_read > 0 {
|
||||||
return Ok(bytes_read);
|
return Ok(bytes_read);
|
||||||
}
|
}
|
||||||
return Err(ReadError::Timeout);
|
return Err(UartReadError::Timeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(bytes_read)
|
Ok(bytes_read)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn read_frame_fragment<const N: usize>(
|
||||||
|
buf: &mut Vec<u8, N>,
|
||||||
|
fragment_pos: usize,
|
||||||
|
fragment_len: usize,
|
||||||
|
uart: &mut usart::BufferedUartRx<'_>,
|
||||||
|
first_byte_timeout: Duration,
|
||||||
|
between_bytes_timeout: Duration,
|
||||||
|
) -> Result<(), UartReadError> {
|
||||||
|
// compute the number of bytes available in the buffer, and the
|
||||||
|
// number of bytes to read
|
||||||
|
let bytes_available = buf[fragment_pos..].len();
|
||||||
|
let bytes_to_read = fragment_len.saturating_sub(bytes_available);
|
||||||
|
if bytes_to_read == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the fragment will not fit in the buffer's available space,
|
||||||
|
// return an error
|
||||||
|
if bytes_to_read > (buf.capacity() - buf.len()) {
|
||||||
|
return Err(UartReadError::BufferCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there aren't enough bytes in the buffer for the
|
||||||
|
// fragment, wait for them to arrive, with a timeout
|
||||||
|
if let Ok(r) = read_with_timeouts(
|
||||||
|
uart,
|
||||||
|
&mut buf[fragment_pos + bytes_available..bytes_to_read],
|
||||||
|
first_byte_timeout,
|
||||||
|
between_bytes_timeout,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
buf.set_len(fragment_pos + bytes_available + r);
|
||||||
|
}
|
||||||
|
if r < bytes_to_read {
|
||||||
|
return Err(UartReadError::Timeout);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(UartReadError::Timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue