From c1c3f607293b510774946c1b04b90a1a2e00c3d7 Mon Sep 17 00:00:00 2001 From: Marvin Gudel Date: Tue, 19 Aug 2025 14:02:08 +0200 Subject: [PATCH 01/11] Featuregate embassy router implementation Signed-off-by: Marvin Gudel --- mctp-estack/Cargo.toml | 3 ++- mctp-estack/src/control.rs | 3 +++ mctp-estack/src/lib.rs | 3 +++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/mctp-estack/Cargo.toml b/mctp-estack/Cargo.toml index 52e4563..8e2c71d 100644 --- a/mctp-estack/Cargo.toml +++ b/mctp-estack/Cargo.toml @@ -11,7 +11,7 @@ rust-version = "1.85" [dependencies] crc = { workspace = true } defmt = { workspace = true, optional = true } -embassy-sync = "0.7" +embassy-sync = { version = "0.7", optional = true } embedded-io-async = { workspace = true } heapless = { workspace = true } log = { workspace = true, optional = true } @@ -33,3 +33,4 @@ default = ["log"] std = ["mctp/std"] log = ["dep:log"] defmt = ["mctp/defmt", "dep:defmt" ] +embassy = ["dep:embassy-sync"] diff --git a/mctp-estack/src/control.rs b/mctp-estack/src/control.rs index 3392912..ebc0e07 100644 --- a/mctp-estack/src/control.rs +++ b/mctp-estack/src/control.rs @@ -7,6 +7,7 @@ //! MCTP Control Protocol implementation use crate::fmt::*; +#[cfg(feature = "embassy")] use crate::Router; use mctp::{AsyncRespChannel, Eid, Error, Listener, MsgIC, MsgType}; use uuid::Uuid; @@ -424,6 +425,7 @@ where } /// A Control Message handler. +#[cfg(feature = "embassy")] pub struct MctpControl<'g, 'r> { rsp_buf: [u8; MAX_MSG_SIZE], types: heapless::Vec, @@ -431,6 +433,7 @@ pub struct MctpControl<'g, 'r> { router: &'g Router<'r>, } +#[cfg(feature = "embassy")] impl<'g, 'r> MctpControl<'g, 'r> { /// Create a new instance. pub fn new(router: &'g Router<'r>) -> Self { diff --git a/mctp-estack/src/lib.rs b/mctp-estack/src/lib.rs index bde1bff..ab09409 100644 --- a/mctp-estack/src/lib.rs +++ b/mctp-estack/src/lib.rs @@ -61,6 +61,7 @@ pub mod control; pub mod fragment; pub mod i2c; mod reassemble; +#[cfg(feature = "embassy")] pub mod router; pub mod serial; pub mod usb; @@ -68,12 +69,14 @@ pub mod usb; mod util; mod proto; +#[cfg(feature = "embassy")] #[rustfmt::skip] #[allow(clippy::needless_lifetimes)] mod zerocopy_channel; use fragment::{Fragmenter, SendOutput}; use reassemble::Reassembler; +#[cfg(feature = "embassy")] pub use router::Router; use crate::fmt::*; From 487988c34caaa4445f0d8ce93e855ad9368fc4bc Mon Sep 17 00:00:00 2001 From: Marvin Gudel Date: Tue, 19 Aug 2025 16:34:04 +0200 Subject: [PATCH 02/11] Fix `unused` warnings Signed-off-by: Marvin Gudel --- mctp-estack/src/control.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mctp-estack/src/control.rs b/mctp-estack/src/control.rs index ebc0e07..d2c0a0b 100644 --- a/mctp-estack/src/control.rs +++ b/mctp-estack/src/control.rs @@ -9,7 +9,9 @@ use crate::fmt::*; #[cfg(feature = "embassy")] use crate::Router; -use mctp::{AsyncRespChannel, Eid, Error, Listener, MsgIC, MsgType}; +#[cfg(feature = "embassy")] +use mctp::{AsyncRespChannel, MsgIC}; +use mctp::{Eid, Error, Listener, MsgType}; use uuid::Uuid; /// A `Result` with a MCTP control completion code as error. @@ -192,7 +194,9 @@ pub struct MctpControlMsg<'a> { work: [u8; 2], } +#[cfg(feature = "embassy")] const MAX_MSG_SIZE: usize = 20; /* largest is Get Endpoint UUID */ +#[cfg(feature = "embassy")] const MAX_MSG_TYPES: usize = 8; impl<'a> MctpControlMsg<'a> { From 153062883de582bee25934d6ca0b6fa4f00a40f1 Mon Sep 17 00:00:00 2001 From: Marvin Gudel Date: Wed, 20 Aug 2025 15:19:52 +0200 Subject: [PATCH 03/11] Add async feature for embedded-io-async serial transport Signed-off-by: Marvin Gudel --- mctp-estack/Cargo.toml | 5 +++-- mctp-estack/README.md | 6 ++++++ mctp-estack/src/lib.rs | 7 +++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/mctp-estack/Cargo.toml b/mctp-estack/Cargo.toml index 8e2c71d..4e0e256 100644 --- a/mctp-estack/Cargo.toml +++ b/mctp-estack/Cargo.toml @@ -12,7 +12,7 @@ rust-version = "1.85" crc = { workspace = true } defmt = { workspace = true, optional = true } embassy-sync = { version = "0.7", optional = true } -embedded-io-async = { workspace = true } +embedded-io-async = { workspace = true, optional = true } heapless = { workspace = true } log = { workspace = true, optional = true } mctp = { workspace = true } @@ -33,4 +33,5 @@ default = ["log"] std = ["mctp/std"] log = ["dep:log"] defmt = ["mctp/defmt", "dep:defmt" ] -embassy = ["dep:embassy-sync"] +embassy = ["dep:embassy-sync", "async"] +async = ["dep:embedded-io-async"] diff --git a/mctp-estack/README.md b/mctp-estack/README.md index e1e39d7..7acde16 100644 --- a/mctp-estack/README.md +++ b/mctp-estack/README.md @@ -3,6 +3,8 @@ [API docs](https://docs.rs/mctp-estack) This is a MCTP stack suitable for embedded devices. +A `async` Router for embassy based applications is available +through the `embassy` feature. A `Router` instance handles feeding MCTP packets to and from user provided MCTP transports, and handles sending receiving MCTP messages @@ -16,3 +18,7 @@ MCTP bridging between ports is supported by the `Router`. The core `Stack` handles IO-less MCTP message reassembly and fragmentation, and MCTP tag tracking. MCTP transport binding packet encoding and decoding is provided for I2C, USB, and serial. + +## Features +- `embassy`: async `Router` for [Embassy](https://embassy.dev/) +- `async`: [embedded-io-async](https://docs.rs/embedded-io-async/0.6.1/embedded_io_async/) serial transport binding (enabled by `embassy` feature) diff --git a/mctp-estack/src/lib.rs b/mctp-estack/src/lib.rs index ab09409..780fa63 100644 --- a/mctp-estack/src/lib.rs +++ b/mctp-estack/src/lib.rs @@ -7,6 +7,8 @@ //! //! This crate provides a MCTP stack that can be embedded in other programs //! or devices. +//! A `async` Router for embassy based applications is available +//! through the `embassy` feature. //! //! A [`Router`] object lets programs use a [`Stack`] with //! MCTP transport binding links. Each *Port* handles transmitting and receiving @@ -20,6 +22,10 @@ //! The IO-less [`Stack`] handles MCTP message formatting and parsing, independent //! of any particular MCTP transport binding. //! +//! ## Features +//! - `embassy`: async `Router` for [Embassy](https://embassy.dev/) +//! - `async`: [embedded-io-async](https://docs.rs/embedded-io-async/0.6.1/embedded_io_async/) serial transport binding (enabled by `embassy` feature) +//! //! ## Configuration //! //! `mctp-estack` uses fixed sizes to be suitable on no-alloc platforms. @@ -63,6 +69,7 @@ pub mod i2c; mod reassemble; #[cfg(feature = "embassy")] pub mod router; +#[cfg(feature = "async")] pub mod serial; pub mod usb; #[macro_use] From f10e737c33cf2413f07b55a7cb3edf7b1034de77 Mon Sep 17 00:00:00 2001 From: leongross Date: Thu, 11 Sep 2025 15:06:08 +0200 Subject: [PATCH 04/11] add sync mctp-estack serial Signed-off-by: leongross Signed-off-by: Marvin Gudel --- Cargo.lock | 1 + Cargo.toml | 1 + mctp-estack/Cargo.toml | 1 + mctp-estack/src/lib.rs | 1 - mctp-estack/src/serial.rs | 154 +++++++++++++++++++++++++++++++-- mctp-estack/tests/roundtrip.rs | 6 ++ 6 files changed, 156 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e327a08..5d9565a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -919,6 +919,7 @@ dependencies = [ "critical-section", "defmt", "embassy-sync", + "embedded-io", "embedded-io-adapters", "embedded-io-async", "env_logger", diff --git a/Cargo.toml b/Cargo.toml index 9e9826f..93bb3d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ defmt = "0.3" deku = { git = "https://github.com/CodeConstruct/deku.git", tag = "cc/deku-v0.19.1/no-alloc-3", default-features = false } embedded-io-adapters = { version = "0.6", features = ["std", "futures-03"] } embedded-io-async = "0.6" +embedded-io = "0.6" enumset = "1.1" env_logger = "0.11.3" heapless = "0.8" diff --git a/mctp-estack/Cargo.toml b/mctp-estack/Cargo.toml index 4e0e256..5064c82 100644 --- a/mctp-estack/Cargo.toml +++ b/mctp-estack/Cargo.toml @@ -12,6 +12,7 @@ rust-version = "1.85" crc = { workspace = true } defmt = { workspace = true, optional = true } embassy-sync = { version = "0.7", optional = true } +embedded-io.workspace = true embedded-io-async = { workspace = true, optional = true } heapless = { workspace = true } log = { workspace = true, optional = true } diff --git a/mctp-estack/src/lib.rs b/mctp-estack/src/lib.rs index 780fa63..8393d25 100644 --- a/mctp-estack/src/lib.rs +++ b/mctp-estack/src/lib.rs @@ -69,7 +69,6 @@ pub mod i2c; mod reassemble; #[cfg(feature = "embassy")] pub mod router; -#[cfg(feature = "async")] pub mod serial; pub mod usb; #[macro_use] diff --git a/mctp-estack/src/serial.rs b/mctp-estack/src/serial.rs index e713096..d769b8b 100644 --- a/mctp-estack/src/serial.rs +++ b/mctp-estack/src/serial.rs @@ -12,8 +12,12 @@ use mctp::{Error, Result}; use crc::Crc; use heapless::Vec; +#[cfg(feature = "embassy")] use embedded_io_async::{Read, Write}; +#[cfg(not(feature = "embassy"))] +use embedded_io::{Read, Write}; + const MCTP_SERIAL_REVISION: u8 = 0x01; // Limited by u8 bytecount field, minus MCTP headers @@ -68,6 +72,7 @@ impl MctpSerialHandler { /// Read a frame. /// /// This is async cancel-safe. + #[cfg(feature = "embassy")] pub async fn recv_async(&mut self, input: &mut impl Read) -> Result<&[u8]> { // TODO: This reads one byte a time, might need a buffering wrapper // for performance. Will require more thought about cancel-safety @@ -96,9 +101,41 @@ impl MctpSerialHandler { } } + /// Read a frame synchronously. + /// This function blocks until at least one byte is available + #[cfg(not(feature = "embassy"))] + pub fn recv(&mut self, input: &mut impl Read) -> Result<&[u8]> { + // TODO: This reads one byte a time, might need a buffering wrapper + // for performance. Will require more thought about cancel-safety + + loop { + let mut b = 0u8; + match input.read(core::slice::from_mut(&mut b)) { + Ok(1) => (), + Ok(0) => { + trace!("Serial EOF"); + return Err(Error::RxFailure); + } + Ok(2..) => unreachable!(), + Err(_e) => { + trace!("Serial read error"); + return Err(Error::RxFailure); + } + } + + if let Some(_p) = self.feed_frame(b) { + return Ok(&self.rxbuf[2..][..self.rxcount]); + } + } + } + + /// Feed a byte into the frame parser state machine. + /// Returns Some(&[u8]) when a complete frame is available, containing the MCTP packet. + /// Returns None if the frame is incomplete. fn feed_frame(&mut self, b: u8) -> Option<&[u8]> { trace!("serial read {:02x}", b); + // State machine from DSP0253 Figure 1 match self.rxpos { Pos::FrameSearch => { if b == FRAMING_FLAG { @@ -181,6 +218,8 @@ impl MctpSerialHandler { None } + /// Asynchronously send a MCTP packet over serial provided by `output`. + #[cfg(feature = "embassy")] pub async fn send_async( &mut self, pkt: &[u8], @@ -191,6 +230,18 @@ impl MctpSerialHandler { .map_err(|_e| Error::TxFailure) } + /// Synchronously send a MCTP packet over serial provided by `output`. + #[cfg(not(feature = "embassy"))] + pub fn send_sync( + &mut self, + pkt: &[u8], + output: &mut impl Write, + ) -> Result<()> { + Self::frame_to_serial(pkt, output).map_err(|_e| Error::TxFailure) + } + + /// Frame a MCTP packet into a serial frame, writing to `output`. + #[cfg(feature = "embassy")] async fn frame_to_serial( p: &[u8], output: &mut W, @@ -214,6 +265,33 @@ impl MctpSerialHandler { Ok(()) } + /// Frame a MCTP packet into a serial frame, writing to `output`. + #[cfg(not(feature = "embassy"))] + fn frame_to_serial( + p: &[u8], + output: &mut W, + ) -> core::result::Result<(), W::Error> + where + W: Write, + { + debug_assert!(p.len() <= u8::MAX.into()); + debug_assert!(p.len() > 4); + + let start = [FRAMING_FLAG, MCTP_SERIAL_REVISION, p.len() as u8]; + let mut cs = CRC_FCS.digest(); + cs.update(&start[1..]); + cs.update(p); + let cs = !cs.finalize(); + + output.write_all(&start)?; + Self::write_escaped(p, output)?; + output.write_all(&cs.to_be_bytes())?; + output.write_all(&[FRAMING_FLAG])?; + Ok(()) + } + + /// Asynchronously write a byte slice to `output`, escaping 0x7e and 0x7d bytes. + #[cfg(feature = "embassy")] async fn write_escaped( p: &[u8], output: &mut W, @@ -239,6 +317,34 @@ impl MctpSerialHandler { } Ok(()) } + + /// Synchronously write a byte slice to `output`, escaping 0x7e and 0x7d bytes. + #[cfg(not(feature = "embassy"))] + fn write_escaped( + p: &[u8], + output: &mut W, + ) -> core::result::Result<(), W::Error> + where + W: Write, + { + for c in + p.split_inclusive(|&b| b == FRAMING_FLAG || b == FRAMING_ESCAPE) + { + let (last, rest) = c.split_last().unwrap(); + match *last { + FRAMING_FLAG => { + output.write_all(rest)?; + output.write_all(&[FRAMING_ESCAPE, FLAG_ESCAPED])?; + } + FRAMING_ESCAPE => { + output.write_all(rest)?; + output.write_all(&[FRAMING_ESCAPE, ESCAPE_ESCAPED])?; + } + _ => output.write_all(c)?, + } + } + Ok(()) + } } impl Default for MctpSerialHandler { @@ -251,9 +357,11 @@ impl Default for MctpSerialHandler { mod tests { use crate::serial::*; use crate::*; - use embedded_io_adapters::futures_03::FromFutures; use proptest::prelude::*; + #[cfg(feature = "embassy")] + use embedded_io_adapters::futures_03::FromFutures; + fn start_log() { let _ = env_logger::Builder::new() .filter(None, log::LevelFilter::Trace) @@ -261,7 +369,8 @@ mod tests { .try_init(); } - async fn do_roundtrip(payload: &[u8]) { + #[cfg(feature = "embassy")] + async fn do_roundtrip_async(payload: &[u8]) { let mut esc = vec![]; let mut s = FromFutures::new(&mut esc); MctpSerialHandler::frame_to_serial(payload, &mut s) @@ -276,26 +385,57 @@ mod tests { debug_assert_eq!(payload, packet); } + #[cfg(not(feature = "embassy"))] + fn do_roundtrip_sync(payload: &[u8]) { + let mut esc = vec![]; + MctpSerialHandler::frame_to_serial(payload, &mut esc).unwrap(); + debug!("{:02x?}", payload); + debug!("{:02x?}", esc); + + let mut h = MctpSerialHandler::new(); + let mut s = esc.as_slice(); + let packet = h.recv(&mut s).unwrap(); + debug_assert_eq!(payload, packet); + } + + #[cfg(feature = "embassy")] #[test] - fn roundtrip_cases() { + fn roundtrip_cases_async() { // Fixed testcases start_log(); smol::block_on(async { for payload in [&[0x01, 0x5d, 0x0d, 0xf4, 0x01, 0x93, 0x7d, 0xcd, 0x36]] { - do_roundtrip(payload).await + do_roundtrip_async(payload).await } }) } + #[cfg(not(feature = "embassy"))] + #[test] + fn roundtrip_cases_sync() { + let test_payload = + [&[0x01, 0x5d, 0x0d, 0xf4, 0x01, 0x93, 0x7d, 0xcd, 0x36]]; + start_log(); + for payload in test_payload { + do_roundtrip_sync(payload) + } + } + proptest! { + #[cfg(feature = "embassy")] #[test] - fn roundtrip_escape(payload in proptest::collection::vec(0..255u8, 5..20)) { + fn roundtrip_escape_async(payload in proptest::collection::vec(0..255u8, 5..20)) { start_log(); + smol::block_on(do_roundtrip_async(&payload)) + } - smol::block_on(do_roundtrip(&payload)) - + #[cfg(not(feature = "embassy"))] + #[test] + fn roundtrip_escape_sync(payload in proptest::collection::vec(0..255u8, 5..20)) { + start_log(); + do_roundtrip_sync(&payload) } } } diff --git a/mctp-estack/tests/roundtrip.rs b/mctp-estack/tests/roundtrip.rs index 9a78cd1..3c8255e 100644 --- a/mctp-estack/tests/roundtrip.rs +++ b/mctp-estack/tests/roundtrip.rs @@ -3,6 +3,11 @@ * Copyright (c) 2025 Code Construct */ +// Roundtrip heavily relies on the router implementation that we currently have +// to remove for a working synchronous implementaion. +// For now, exclude the entire roundtrip test. +#![cfg(feature = "embassy")] + #[allow(unused)] use log::{debug, error, info, trace, warn}; @@ -10,6 +15,7 @@ use mctp::{Eid, MsgType}; use mctp::{AsyncListener, AsyncReqChannel, AsyncRespChannel}; use mctp_estack::config::NUM_RECEIVE; + use mctp_estack::router::{ Port, PortId, PortLookup, PortTop, RouterAsyncReqChannel, }; From 996225a132bb260ecf6447851b4a6bdce64e396d Mon Sep 17 00:00:00 2001 From: leongross Date: Tue, 16 Sep 2025 16:17:36 +0200 Subject: [PATCH 05/11] update tests Signed-off-by: leongross Signed-off-by: Marvin Gudel --- mctp-estack/src/serial.rs | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/mctp-estack/src/serial.rs b/mctp-estack/src/serial.rs index d769b8b..98b551b 100644 --- a/mctp-estack/src/serial.rs +++ b/mctp-estack/src/serial.rs @@ -108,6 +108,7 @@ impl MctpSerialHandler { // TODO: This reads one byte a time, might need a buffering wrapper // for performance. Will require more thought about cancel-safety + trace!("recv trace"); loop { let mut b = 0u8; match input.read(core::slice::from_mut(&mut b)) { @@ -362,9 +363,12 @@ mod tests { #[cfg(feature = "embassy")] use embedded_io_adapters::futures_03::FromFutures; + static TEST_DATA_ROUNTRIP: [&[u8]; 1] = + [&[0x01, 0x5d, 0x0d, 0xf4, 0x01, 0x93, 0x7d, 0xcd, 0x36]]; + fn start_log() { let _ = env_logger::Builder::new() - .filter(None, log::LevelFilter::Trace) + .filter(None, log::LevelFilter::Debug) .is_test(true) .try_init(); } @@ -376,25 +380,29 @@ mod tests { MctpSerialHandler::frame_to_serial(payload, &mut s) .await .unwrap(); - debug!("{:02x?}", payload); - debug!("{:02x?}", esc); + + debug!("payload {:02x?}", payload); + debug!("esc {:02x?}", esc); let mut h = MctpSerialHandler::new(); let mut s = FromFutures::new(esc.as_slice()); let packet = h.recv_async(&mut s).await.unwrap(); + debug!("packet {:02x?}", packet); debug_assert_eq!(payload, packet); } #[cfg(not(feature = "embassy"))] fn do_roundtrip_sync(payload: &[u8]) { + start_log(); let mut esc = vec![]; MctpSerialHandler::frame_to_serial(payload, &mut esc).unwrap(); - debug!("{:02x?}", payload); - debug!("{:02x?}", esc); + debug!("payload {:02x?}", payload); + debug!("esc {:02x?}", esc); let mut h = MctpSerialHandler::new(); let mut s = esc.as_slice(); let packet = h.recv(&mut s).unwrap(); + debug!("packet {:02x?}", packet); debug_assert_eq!(payload, packet); } @@ -404,9 +412,7 @@ mod tests { // Fixed testcases start_log(); smol::block_on(async { - for payload in - [&[0x01, 0x5d, 0x0d, 0xf4, 0x01, 0x93, 0x7d, 0xcd, 0x36]] - { + for payload in TEST_DATA_ROUNTRIP { do_roundtrip_async(payload).await } }) @@ -415,10 +421,8 @@ mod tests { #[cfg(not(feature = "embassy"))] #[test] fn roundtrip_cases_sync() { - let test_payload = - [&[0x01, 0x5d, 0x0d, 0xf4, 0x01, 0x93, 0x7d, 0xcd, 0x36]]; start_log(); - for payload in test_payload { + for payload in TEST_DATA_ROUNTRIP { do_roundtrip_sync(payload) } } From 03494e8280e0f859ff2355756412c9a9c7d3a658 Mon Sep 17 00:00:00 2001 From: leongross Date: Wed, 17 Sep 2025 16:37:00 +0200 Subject: [PATCH 06/11] test: add test for sync and async code Signed-off-by: leongross Signed-off-by: Marvin Gudel --- ci/runtests.sh | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/ci/runtests.sh b/ci/runtests.sh index c54cfec..232d267 100755 --- a/ci/runtests.sh +++ b/ci/runtests.sh @@ -53,6 +53,25 @@ cargo build --target thumbv7em-none-eabihf --features defmt --no-default-feature cargo build --features log ) -cargo doc +FEATURES_ASYNC="embassy" +FEATURES_SYNC="" + +declare -a FEATURES=( + "$FEATURES_SYNC" + "$FEATURES_ASYNC" +) + +# mctp-estack, sync an async +( +cd mctp-estack +for feature in "${FEATURES[@]}"; do + cargo test --features="$feature" +done; +) + +# run cargo doc tests +for feature in "${FEATURES[@]}"; do + cargo doc --features="$feature" +done; echo success From 57e11b472bd778ac947052ff27224d33a9143469 Mon Sep 17 00:00:00 2001 From: leongross Date: Wed, 17 Sep 2025 16:39:17 +0200 Subject: [PATCH 07/11] test: apply shellcheck fix suggestions Signed-off-by: leongross Signed-off-by: Marvin Gudel --- ci/runtests.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ci/runtests.sh b/ci/runtests.sh index 232d267..04a0bf7 100755 --- a/ci/runtests.sh +++ b/ci/runtests.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -v set -e @@ -15,7 +15,7 @@ cargo fmt -- --check # Check everything first cargo check --all-targets --locked -if [ -z "NO_CLIPPY" ]; then +if [ -z "$NO_CLIPPY" ]; then cargo clippy --all-targets fi @@ -27,14 +27,14 @@ cargo test NOSTD_CRATES="mctp pldm pldm-fw pldm-platform pldm-file" for c in $NOSTD_CRATES; do ( - cd $c + cd "$c" cargo build --target thumbv7em-none-eabihf --no-default-features ) done ALLOC_CRATES="pldm pldm-platform pldm-file" for c in $ALLOC_CRATES; do ( - cd $c + cd "$c" cargo build --target thumbv7em-none-eabihf --no-default-features --features alloc ) done From 9183ad57f8df311b7de54792c289e4a59c594004 Mon Sep 17 00:00:00 2001 From: Marvin Gudel Date: Mon, 13 Oct 2025 16:30:51 +0200 Subject: [PATCH 08/11] Improve docs, hide async features behind single `async` feature flag Signed-off-by: jonas loeffelholz Signed-off-by: Marvin Gudel --- mctp-estack/Cargo.toml | 3 +-- mctp-estack/src/control.rs | 12 ++++++------ mctp-estack/src/lib.rs | 33 +++++++++++++++------------------ mctp-estack/src/serial.rs | 34 +++++++++++++++++----------------- mctp-estack/tests/roundtrip.rs | 2 +- standalone/Cargo.toml | 2 +- 6 files changed, 41 insertions(+), 45 deletions(-) diff --git a/mctp-estack/Cargo.toml b/mctp-estack/Cargo.toml index 5064c82..ef3bc25 100644 --- a/mctp-estack/Cargo.toml +++ b/mctp-estack/Cargo.toml @@ -34,5 +34,4 @@ default = ["log"] std = ["mctp/std"] log = ["dep:log"] defmt = ["mctp/defmt", "dep:defmt" ] -embassy = ["dep:embassy-sync", "async"] -async = ["dep:embedded-io-async"] +async = ["dep:embedded-io-async", "dep:embassy-sync"] diff --git a/mctp-estack/src/control.rs b/mctp-estack/src/control.rs index d2c0a0b..2807fd4 100644 --- a/mctp-estack/src/control.rs +++ b/mctp-estack/src/control.rs @@ -7,9 +7,9 @@ //! MCTP Control Protocol implementation use crate::fmt::*; -#[cfg(feature = "embassy")] +#[cfg(feature = "async")] use crate::Router; -#[cfg(feature = "embassy")] +#[cfg(feature = "async")] use mctp::{AsyncRespChannel, MsgIC}; use mctp::{Eid, Error, Listener, MsgType}; use uuid::Uuid; @@ -194,9 +194,9 @@ pub struct MctpControlMsg<'a> { work: [u8; 2], } -#[cfg(feature = "embassy")] +#[cfg(feature = "async")] const MAX_MSG_SIZE: usize = 20; /* largest is Get Endpoint UUID */ -#[cfg(feature = "embassy")] +#[cfg(feature = "async")] const MAX_MSG_TYPES: usize = 8; impl<'a> MctpControlMsg<'a> { @@ -429,7 +429,7 @@ where } /// A Control Message handler. -#[cfg(feature = "embassy")] +#[cfg(feature = "async")] pub struct MctpControl<'g, 'r> { rsp_buf: [u8; MAX_MSG_SIZE], types: heapless::Vec, @@ -437,7 +437,7 @@ pub struct MctpControl<'g, 'r> { router: &'g Router<'r>, } -#[cfg(feature = "embassy")] +#[cfg(feature = "async")] impl<'g, 'r> MctpControl<'g, 'r> { /// Create a new instance. pub fn new(router: &'g Router<'r>) -> Self { diff --git a/mctp-estack/src/lib.rs b/mctp-estack/src/lib.rs index 8393d25..b3c76c3 100644 --- a/mctp-estack/src/lib.rs +++ b/mctp-estack/src/lib.rs @@ -5,26 +5,22 @@ //! # MCTP Stack //! -//! This crate provides a MCTP stack that can be embedded in other programs -//! or devices. -//! A `async` Router for embassy based applications is available -//! through the `embassy` feature. -//! -//! A [`Router`] object lets programs use a [`Stack`] with -//! MCTP transport binding links. Each *Port* handles transmitting and receiving -//! packets independently. Messages destined for the stack's own EID will -//! be passed to applications. -//! -//! Applications can create [`router::RouterAsyncListener`] and [`router::RouterAsyncReqChannel`] -//! instances to communicate over MCTP. Those implement the standard [`mctp` crate](mctp) -//! async traits. +//! This crate provides a MCTP stack and transport bindings, +//! that can be embedded in other programs or devices. //! //! The IO-less [`Stack`] handles MCTP message formatting and parsing, independent //! of any particular MCTP transport binding. //! +//! A Router for *async* applications is available +//! through the `async` feature. +//! The async `Router` lets programs use a `Stack` +//! by providing implementations for the standard [`mctp` crate](mctp) async traits. +//! Transport bindings are provided by *Ports* which handle transmitting and receiving +//! packets independently. Messages destined for the stack's own EID will +//! be passed to applications. +//! //! ## Features -//! - `embassy`: async `Router` for [Embassy](https://embassy.dev/) -//! - `async`: [embedded-io-async](https://docs.rs/embedded-io-async/0.6.1/embedded_io_async/) serial transport binding (enabled by `embassy` feature) +//! - `async`: [embedded-io-async](https://docs.rs/embedded-io-async/0.6.1/embedded_io_async/) serial transport binding and async Router //! //! ## Configuration //! @@ -41,6 +37,7 @@ // those reworked when using the log crate either. #![allow(clippy::uninlined_format_args)] #![warn(clippy::unused_async)] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] #[cfg(test)] #[macro_use] @@ -67,7 +64,7 @@ pub mod control; pub mod fragment; pub mod i2c; mod reassemble; -#[cfg(feature = "embassy")] +#[cfg(feature = "async")] pub mod router; pub mod serial; pub mod usb; @@ -75,14 +72,14 @@ pub mod usb; mod util; mod proto; -#[cfg(feature = "embassy")] +#[cfg(feature = "async")] #[rustfmt::skip] #[allow(clippy::needless_lifetimes)] mod zerocopy_channel; use fragment::{Fragmenter, SendOutput}; use reassemble::Reassembler; -#[cfg(feature = "embassy")] +#[cfg(feature = "async")] pub use router::Router; use crate::fmt::*; diff --git a/mctp-estack/src/serial.rs b/mctp-estack/src/serial.rs index 98b551b..b042d8a 100644 --- a/mctp-estack/src/serial.rs +++ b/mctp-estack/src/serial.rs @@ -12,10 +12,10 @@ use mctp::{Error, Result}; use crc::Crc; use heapless::Vec; -#[cfg(feature = "embassy")] +#[cfg(feature = "async")] use embedded_io_async::{Read, Write}; -#[cfg(not(feature = "embassy"))] +#[cfg(not(feature = "async"))] use embedded_io::{Read, Write}; const MCTP_SERIAL_REVISION: u8 = 0x01; @@ -72,7 +72,7 @@ impl MctpSerialHandler { /// Read a frame. /// /// This is async cancel-safe. - #[cfg(feature = "embassy")] + #[cfg(feature = "async")] pub async fn recv_async(&mut self, input: &mut impl Read) -> Result<&[u8]> { // TODO: This reads one byte a time, might need a buffering wrapper // for performance. Will require more thought about cancel-safety @@ -103,7 +103,7 @@ impl MctpSerialHandler { /// Read a frame synchronously. /// This function blocks until at least one byte is available - #[cfg(not(feature = "embassy"))] + #[cfg(not(feature = "async"))] pub fn recv(&mut self, input: &mut impl Read) -> Result<&[u8]> { // TODO: This reads one byte a time, might need a buffering wrapper // for performance. Will require more thought about cancel-safety @@ -220,7 +220,7 @@ impl MctpSerialHandler { } /// Asynchronously send a MCTP packet over serial provided by `output`. - #[cfg(feature = "embassy")] + #[cfg(feature = "async")] pub async fn send_async( &mut self, pkt: &[u8], @@ -232,7 +232,7 @@ impl MctpSerialHandler { } /// Synchronously send a MCTP packet over serial provided by `output`. - #[cfg(not(feature = "embassy"))] + #[cfg(not(feature = "async"))] pub fn send_sync( &mut self, pkt: &[u8], @@ -242,7 +242,7 @@ impl MctpSerialHandler { } /// Frame a MCTP packet into a serial frame, writing to `output`. - #[cfg(feature = "embassy")] + #[cfg(feature = "async")] async fn frame_to_serial( p: &[u8], output: &mut W, @@ -267,7 +267,7 @@ impl MctpSerialHandler { } /// Frame a MCTP packet into a serial frame, writing to `output`. - #[cfg(not(feature = "embassy"))] + #[cfg(not(feature = "async"))] fn frame_to_serial( p: &[u8], output: &mut W, @@ -292,7 +292,7 @@ impl MctpSerialHandler { } /// Asynchronously write a byte slice to `output`, escaping 0x7e and 0x7d bytes. - #[cfg(feature = "embassy")] + #[cfg(feature = "async")] async fn write_escaped( p: &[u8], output: &mut W, @@ -320,7 +320,7 @@ impl MctpSerialHandler { } /// Synchronously write a byte slice to `output`, escaping 0x7e and 0x7d bytes. - #[cfg(not(feature = "embassy"))] + #[cfg(not(feature = "async"))] fn write_escaped( p: &[u8], output: &mut W, @@ -360,7 +360,7 @@ mod tests { use crate::*; use proptest::prelude::*; - #[cfg(feature = "embassy")] + #[cfg(feature = "async")] use embedded_io_adapters::futures_03::FromFutures; static TEST_DATA_ROUNTRIP: [&[u8]; 1] = @@ -373,7 +373,7 @@ mod tests { .try_init(); } - #[cfg(feature = "embassy")] + #[cfg(feature = "async")] async fn do_roundtrip_async(payload: &[u8]) { let mut esc = vec![]; let mut s = FromFutures::new(&mut esc); @@ -391,7 +391,7 @@ mod tests { debug_assert_eq!(payload, packet); } - #[cfg(not(feature = "embassy"))] + #[cfg(not(feature = "async"))] fn do_roundtrip_sync(payload: &[u8]) { start_log(); let mut esc = vec![]; @@ -406,7 +406,7 @@ mod tests { debug_assert_eq!(payload, packet); } - #[cfg(feature = "embassy")] + #[cfg(feature = "async")] #[test] fn roundtrip_cases_async() { // Fixed testcases @@ -418,7 +418,7 @@ mod tests { }) } - #[cfg(not(feature = "embassy"))] + #[cfg(not(feature = "async"))] #[test] fn roundtrip_cases_sync() { start_log(); @@ -428,14 +428,14 @@ mod tests { } proptest! { - #[cfg(feature = "embassy")] + #[cfg(feature = "async")] #[test] fn roundtrip_escape_async(payload in proptest::collection::vec(0..255u8, 5..20)) { start_log(); smol::block_on(do_roundtrip_async(&payload)) } - #[cfg(not(feature = "embassy"))] + #[cfg(not(feature = "async"))] #[test] fn roundtrip_escape_sync(payload in proptest::collection::vec(0..255u8, 5..20)) { start_log(); diff --git a/mctp-estack/tests/roundtrip.rs b/mctp-estack/tests/roundtrip.rs index 3c8255e..33fdfce 100644 --- a/mctp-estack/tests/roundtrip.rs +++ b/mctp-estack/tests/roundtrip.rs @@ -6,7 +6,7 @@ // Roundtrip heavily relies on the router implementation that we currently have // to remove for a working synchronous implementaion. // For now, exclude the entire roundtrip test. -#![cfg(feature = "embassy")] +#![cfg(feature = "async")] #[allow(unused)] use log::{debug, error, info, trace, warn}; diff --git a/standalone/Cargo.toml b/standalone/Cargo.toml index 14971b0..6a2990d 100644 --- a/standalone/Cargo.toml +++ b/standalone/Cargo.toml @@ -10,7 +10,7 @@ categories = ["network-programming"] [dependencies] embedded-io-async = { workspace = true } log = { workspace = true } -mctp-estack = { workspace = true, default-features = true } +mctp-estack = { workspace = true, default-features = true, features = ["async"] } mctp = { workspace = true } smol = { workspace = true } From c05b5cb8e50dcbb81a74ee611038aa5cad67c02f Mon Sep 17 00:00:00 2001 From: Marvin Gudel Date: Mon, 27 Oct 2025 16:26:30 +0100 Subject: [PATCH 09/11] Fix lints and CI Signed-off-by: Marvin Gudel --- ci/runtests.sh | 2 +- mctp-estack/src/fragment.rs | 2 +- mctp-usb-embassy/Cargo.toml | 2 +- pldm-file/examples/host.rs | 4 +--- pldm-platform/examples/decodepdr.rs | 4 ++-- 5 files changed, 6 insertions(+), 8 deletions(-) diff --git a/ci/runtests.sh b/ci/runtests.sh index 04a0bf7..a046c86 100755 --- a/ci/runtests.sh +++ b/ci/runtests.sh @@ -53,7 +53,7 @@ cargo build --target thumbv7em-none-eabihf --features defmt --no-default-feature cargo build --features log ) -FEATURES_ASYNC="embassy" +FEATURES_ASYNC="async" FEATURES_SYNC="" declare -a FEATURES=( diff --git a/mctp-estack/src/fragment.rs b/mctp-estack/src/fragment.rs index cfd360a..1c20b54 100644 --- a/mctp-estack/src/fragment.rs +++ b/mctp-estack/src/fragment.rs @@ -147,7 +147,7 @@ impl Fragmenter { rest = &mut rest[1..]; } - let Ok(n) = self.reader.read(payload, &mut rest) else { + let Ok(n) = self.reader.read(payload, rest) else { return SendOutput::failure(Error::BadArgument, self); }; let rest = &rest[n..]; diff --git a/mctp-usb-embassy/Cargo.toml b/mctp-usb-embassy/Cargo.toml index b13dc35..2c35674 100644 --- a/mctp-usb-embassy/Cargo.toml +++ b/mctp-usb-embassy/Cargo.toml @@ -15,7 +15,7 @@ embassy-usb-driver = { version = "0.2" } embassy-usb = { version = "0.5", default-features = false } heapless = { workspace = true } log = { workspace = true, optional = true } -mctp-estack = { workspace = true } +mctp-estack = { workspace = true, features = ["async"] } mctp = { workspace = true, default-features = false } [features] diff --git a/pldm-file/examples/host.rs b/pldm-file/examples/host.rs index 87b364a..a03e613 100644 --- a/pldm-file/examples/host.rs +++ b/pldm-file/examples/host.rs @@ -12,8 +12,6 @@ use std::io::{Read, Seek, SeekFrom}; use std::os::unix::fs::MetadataExt; use std::time::{Duration, Instant}; -use argh; - /// PLDM file host #[derive(argh::FromArgs)] struct Args { @@ -142,7 +140,7 @@ fn read_whole(f: &mut File, buf: &mut [u8]) -> std::io::Result { } } // Full output - return Ok(total); + Ok(total) } struct Speed { diff --git a/pldm-platform/examples/decodepdr.rs b/pldm-platform/examples/decodepdr.rs index 5eec163..c286a45 100644 --- a/pldm-platform/examples/decodepdr.rs +++ b/pldm-platform/examples/decodepdr.rs @@ -22,7 +22,7 @@ fn main() { }) .unwrap(); println!("rsp {pdrrsp:?}"); - assert!(rest.len() == 0); + assert!(rest.is_empty()); let ((rest, _), pdr) = Pdr::from_bytes((&pdrrsp.record_data, 0)) .map_err(|e| { @@ -33,7 +33,7 @@ fn main() { if !rest.is_empty() { panic!("Extra PDR response"); } - assert!(rest.len() == 0); + assert!(rest.is_empty()); println!("PDR {pdr:?}"); } From a590d28b7f526dd8332720e31d14e2c4faa529b7 Mon Sep 17 00:00:00 2001 From: Marvin Gudel Date: Tue, 18 Nov 2025 11:23:39 +0100 Subject: [PATCH 10/11] Add `async` to default features, correct and improve documentation Signed-off-by: Marvin Gudel --- mctp-estack/Cargo.toml | 2 +- mctp-estack/README.md | 9 ++++----- mctp-estack/src/lib.rs | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/mctp-estack/Cargo.toml b/mctp-estack/Cargo.toml index ef3bc25..aa3018e 100644 --- a/mctp-estack/Cargo.toml +++ b/mctp-estack/Cargo.toml @@ -30,7 +30,7 @@ smol = { workspace = true } [features] -default = ["log"] +default = ["log", "async"] std = ["mctp/std"] log = ["dep:log"] defmt = ["mctp/defmt", "dep:defmt" ] diff --git a/mctp-estack/README.md b/mctp-estack/README.md index 7acde16..a1ddf0d 100644 --- a/mctp-estack/README.md +++ b/mctp-estack/README.md @@ -3,12 +3,12 @@ [API docs](https://docs.rs/mctp-estack) This is a MCTP stack suitable for embedded devices. -A `async` Router for embassy based applications is available -through the `embassy` feature. +A `async` Router for [Embassy](https://embassy.dev/) (or other _async runtime_) +based applications is available through the `async` feature. A `Router` instance handles feeding MCTP packets to and from user provided MCTP transports, and handles sending receiving MCTP messages -from applications using the `mctp` crate async traits. +from applications using the `mctp` crate _async_ traits. Applications using MCTP can create `RouterAsyncListener` and `RouterAsyncReqChannel` instances. @@ -20,5 +20,4 @@ and MCTP tag tracking. MCTP transport binding packet encoding and decoding is provided for I2C, USB, and serial. ## Features -- `embassy`: async `Router` for [Embassy](https://embassy.dev/) -- `async`: [embedded-io-async](https://docs.rs/embedded-io-async/0.6.1/embedded_io_async/) serial transport binding (enabled by `embassy` feature) +- `async`: _async_ router implementing `mctp` crate _async_ traits diff --git a/mctp-estack/src/lib.rs b/mctp-estack/src/lib.rs index b3c76c3..1a0c037 100644 --- a/mctp-estack/src/lib.rs +++ b/mctp-estack/src/lib.rs @@ -20,7 +20,7 @@ //! be passed to applications. //! //! ## Features -//! - `async`: [embedded-io-async](https://docs.rs/embedded-io-async/0.6.1/embedded_io_async/) serial transport binding and async Router +//! - `async`: _async_ router implementing [`mctp` crate](mctp) _async_ traits //! //! ## Configuration //! From fafe92f6fcadf6e57683b91757fad9933ddd223d Mon Sep 17 00:00:00 2001 From: Marvin Gudel Date: Tue, 18 Nov 2025 12:03:08 +0100 Subject: [PATCH 11/11] Remove feature gate from serial async features Signed-off-by: Marvin Gudel --- mctp-estack/Cargo.toml | 4 +-- mctp-estack/src/serial.rs | 68 +++++++++++++++++---------------------- 2 files changed, 31 insertions(+), 41 deletions(-) diff --git a/mctp-estack/Cargo.toml b/mctp-estack/Cargo.toml index aa3018e..5502fa1 100644 --- a/mctp-estack/Cargo.toml +++ b/mctp-estack/Cargo.toml @@ -13,7 +13,7 @@ crc = { workspace = true } defmt = { workspace = true, optional = true } embassy-sync = { version = "0.7", optional = true } embedded-io.workspace = true -embedded-io-async = { workspace = true, optional = true } +embedded-io-async.workspace = true heapless = { workspace = true } log = { workspace = true, optional = true } mctp = { workspace = true } @@ -34,4 +34,4 @@ default = ["log", "async"] std = ["mctp/std"] log = ["dep:log"] defmt = ["mctp/defmt", "dep:defmt" ] -async = ["dep:embedded-io-async", "dep:embassy-sync"] +async = ["dep:embassy-sync"] diff --git a/mctp-estack/src/serial.rs b/mctp-estack/src/serial.rs index b042d8a..606d107 100644 --- a/mctp-estack/src/serial.rs +++ b/mctp-estack/src/serial.rs @@ -4,6 +4,8 @@ */ //! A MCTP serial transport binding, DSP0253 +//! +//! Supporting both `embedded-io` and `embedded-io-async`. #[allow(unused)] use crate::fmt::{debug, error, info, trace, warn}; @@ -12,10 +14,8 @@ use mctp::{Error, Result}; use crc::Crc; use heapless::Vec; -#[cfg(feature = "async")] -use embedded_io_async::{Read, Write}; +use embedded_io_async::{Read as AsyncRead, Write as AsyncWrite}; -#[cfg(not(feature = "async"))] use embedded_io::{Read, Write}; const MCTP_SERIAL_REVISION: u8 = 0x01; @@ -72,8 +72,10 @@ impl MctpSerialHandler { /// Read a frame. /// /// This is async cancel-safe. - #[cfg(feature = "async")] - pub async fn recv_async(&mut self, input: &mut impl Read) -> Result<&[u8]> { + pub async fn recv_async( + &mut self, + input: &mut impl AsyncRead, + ) -> Result<&[u8]> { // TODO: This reads one byte a time, might need a buffering wrapper // for performance. Will require more thought about cancel-safety @@ -101,13 +103,14 @@ impl MctpSerialHandler { } } - /// Read a frame synchronously. - /// This function blocks until at least one byte is available - #[cfg(not(feature = "async"))] - pub fn recv(&mut self, input: &mut impl Read) -> Result<&[u8]> { - // TODO: This reads one byte a time, might need a buffering wrapper - // for performance. Will require more thought about cancel-safety - + /// Read a frame synchronously + /// + /// This function blocks until at least one byte is available. + /// + /// Reads one byte at a time from the [reader](Read). + /// If buffering is needed for performance reasons, + /// this has to be provided by the reader. + pub fn recv_sync(&mut self, input: &mut impl Read) -> Result<&[u8]> { trace!("recv trace"); loop { let mut b = 0u8; @@ -220,35 +223,32 @@ impl MctpSerialHandler { } /// Asynchronously send a MCTP packet over serial provided by `output`. - #[cfg(feature = "async")] pub async fn send_async( &mut self, pkt: &[u8], - output: &mut impl Write, + output: &mut impl AsyncWrite, ) -> Result<()> { - Self::frame_to_serial(pkt, output) + Self::frame_to_serial_async(pkt, output) .await .map_err(|_e| Error::TxFailure) } /// Synchronously send a MCTP packet over serial provided by `output`. - #[cfg(not(feature = "async"))] pub fn send_sync( &mut self, pkt: &[u8], output: &mut impl Write, ) -> Result<()> { - Self::frame_to_serial(pkt, output).map_err(|_e| Error::TxFailure) + Self::frame_to_serial_sync(pkt, output).map_err(|_e| Error::TxFailure) } /// Frame a MCTP packet into a serial frame, writing to `output`. - #[cfg(feature = "async")] - async fn frame_to_serial( + async fn frame_to_serial_async( p: &[u8], output: &mut W, ) -> core::result::Result<(), W::Error> where - W: Write, + W: AsyncWrite, { debug_assert!(p.len() <= u8::MAX.into()); debug_assert!(p.len() > 4); @@ -260,15 +260,14 @@ impl MctpSerialHandler { let cs = !cs.finalize(); output.write_all(&start).await?; - Self::write_escaped(p, output).await?; + Self::write_escaped_async(p, output).await?; output.write_all(&cs.to_be_bytes()).await?; output.write_all(&[FRAMING_FLAG]).await?; Ok(()) } /// Frame a MCTP packet into a serial frame, writing to `output`. - #[cfg(not(feature = "async"))] - fn frame_to_serial( + fn frame_to_serial_sync( p: &[u8], output: &mut W, ) -> core::result::Result<(), W::Error> @@ -285,20 +284,19 @@ impl MctpSerialHandler { let cs = !cs.finalize(); output.write_all(&start)?; - Self::write_escaped(p, output)?; + Self::write_escaped_sync(p, output)?; output.write_all(&cs.to_be_bytes())?; output.write_all(&[FRAMING_FLAG])?; Ok(()) } /// Asynchronously write a byte slice to `output`, escaping 0x7e and 0x7d bytes. - #[cfg(feature = "async")] - async fn write_escaped( + async fn write_escaped_async( p: &[u8], output: &mut W, ) -> core::result::Result<(), W::Error> where - W: Write, + W: AsyncWrite, { for c in p.split_inclusive(|&b| b == FRAMING_FLAG || b == FRAMING_ESCAPE) @@ -320,8 +318,7 @@ impl MctpSerialHandler { } /// Synchronously write a byte slice to `output`, escaping 0x7e and 0x7d bytes. - #[cfg(not(feature = "async"))] - fn write_escaped( + fn write_escaped_sync( p: &[u8], output: &mut W, ) -> core::result::Result<(), W::Error> @@ -360,7 +357,6 @@ mod tests { use crate::*; use proptest::prelude::*; - #[cfg(feature = "async")] use embedded_io_adapters::futures_03::FromFutures; static TEST_DATA_ROUNTRIP: [&[u8]; 1] = @@ -373,11 +369,10 @@ mod tests { .try_init(); } - #[cfg(feature = "async")] async fn do_roundtrip_async(payload: &[u8]) { let mut esc = vec![]; let mut s = FromFutures::new(&mut esc); - MctpSerialHandler::frame_to_serial(payload, &mut s) + MctpSerialHandler::frame_to_serial_async(payload, &mut s) .await .unwrap(); @@ -391,22 +386,20 @@ mod tests { debug_assert_eq!(payload, packet); } - #[cfg(not(feature = "async"))] fn do_roundtrip_sync(payload: &[u8]) { start_log(); let mut esc = vec![]; - MctpSerialHandler::frame_to_serial(payload, &mut esc).unwrap(); + MctpSerialHandler::frame_to_serial_sync(payload, &mut esc).unwrap(); debug!("payload {:02x?}", payload); debug!("esc {:02x?}", esc); let mut h = MctpSerialHandler::new(); let mut s = esc.as_slice(); - let packet = h.recv(&mut s).unwrap(); + let packet = h.recv_sync(&mut s).unwrap(); debug!("packet {:02x?}", packet); debug_assert_eq!(payload, packet); } - #[cfg(feature = "async")] #[test] fn roundtrip_cases_async() { // Fixed testcases @@ -418,7 +411,6 @@ mod tests { }) } - #[cfg(not(feature = "async"))] #[test] fn roundtrip_cases_sync() { start_log(); @@ -428,14 +420,12 @@ mod tests { } proptest! { - #[cfg(feature = "async")] #[test] fn roundtrip_escape_async(payload in proptest::collection::vec(0..255u8, 5..20)) { start_log(); smol::block_on(do_roundtrip_async(&payload)) } - #[cfg(not(feature = "async"))] #[test] fn roundtrip_escape_sync(payload in proptest::collection::vec(0..255u8, 5..20)) { start_log();