Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 170 additions & 11 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion embedded-service/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ defmt = { workspace = true, optional = true }
document-features.workspace = true
embassy-sync.workspace = true
embassy-time.workspace = true
embassy-futures.workspace = true
embedded-batteries-async.workspace = true
embedded-cfu-protocol.workspace = true
embedded-hal-async.workspace = true
Expand Down Expand Up @@ -49,7 +50,6 @@ cortex-m.workspace = true

[dev-dependencies]
critical-section = { workspace = true, features = ["std"] }
embassy-futures.workspace = true
embassy-sync = { workspace = true, features = ["std"] }
embassy-time = { workspace = true, features = ["std", "generic-queue-8"] }
embassy-time-driver = { workspace = true }
Expand Down
43 changes: 43 additions & 0 deletions embedded-service/src/event.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//! Common traits for event senders and receivers

use embassy_sync::channel::{DynamicReceiver, DynamicSender};
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing import for Future. The trait methods return impl Future but there's no use core::future::Future; statement in this file.

Suggested change
use embassy_sync::channel::{DynamicReceiver, DynamicSender};
use embassy_sync::channel::{DynamicReceiver, DynamicSender};
use core::future::Future;

Copilot uses AI. Check for mistakes.

/// Common event sender trait
pub trait Sender<E> {
/// Attempt to send an event
///
/// Return none if the event cannot currently be sent
fn try_send(&mut self, event: E) -> Option<()>;
/// Send an event
fn send(&mut self, event: E) -> impl Future<Output = ()>;
}
Comment on lines +5 to +13
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file defines Sender::send and Receiver::wait_next returning impl Future, but Future is never imported, so this will fail to compile. Add use core::future::Future; (or fully qualify core::future::Future) at the top of the file so the trait bounds resolve.

Copilot uses AI. Check for mistakes.

/// Common event receiver trait
pub trait Receiver<E> {
/// Attempt to receive an event
///
/// Return none if there are no pending events
fn try_next(&mut self) -> Option<E>;
/// Receiver an event
Comment on lines +5 to +21
Copy link

Copilot AI Jan 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Sender and Receiver traits lack documentation. Consider adding doc comments explaining their purpose, when they should be used, and any invariants. For example, document whether try_send returning None means the channel is full or the receiver is closed.

Suggested change
/// Common event sender trait
pub trait Sender<E> {
/// Attempt to send an event
///
/// Return none if the event cannot currently be sent
fn try_send(&mut self, event: E) -> Option<()>;
/// Send an event
fn send(&mut self, event: E) -> impl Future<Output = ()>;
}
/// Common event receiver trait
pub trait Receiver<E> {
/// Attempt to receive an event
///
/// Return none if there are no pending events
fn try_next(&mut self) -> Option<E>;
/// Receiver an event
/// Abstraction over components that can send events of type `E`.
///
/// This trait provides a common interface for event senders backed by
/// channel-like primitives (for example, [`DynamicSender`]). It allows code
/// to be written against this trait instead of a concrete channel type.
///
/// # Semantics
///
/// - [`Sender::try_send`] is **non-blocking**: it attempts to enqueue an
/// event immediately and returns:
/// - `Some(())` if the event was successfully enqueued.
/// - `None` if the event cannot currently be sent. In this crate's
/// implementations, this covers both the channel being full and the
/// receiver side being closed.
/// - [`Sender::send`] returns a future that will **asynchronously** send
/// the event according to the underlying implementation's semantics.
pub trait Sender<E> {
/// Attempt to send an event without blocking.
///
/// Returns `Some(())` on success.
///
/// Returns `None` if the event cannot currently be sent. For the
/// provided `DynamicSender` implementation, this occurs when the
/// underlying channel is full or the receiver side has been closed.
fn try_send(&mut self, event: E) -> Option<()>;
/// Send an event, waiting asynchronously until it can be enqueued.
///
/// The returned future completes once the event has been sent according
/// to the semantics of the underlying sender implementation.
fn send(&mut self, event: E) -> impl Future<Output = ()>;
}
/// Abstraction over components that can receive events of type `E`.
///
/// This trait provides a common interface for event receivers backed by
/// channel-like primitives (for example, [`DynamicReceiver`]). It allows
/// consumers to be written against this trait instead of a concrete channel
/// type.
///
/// # Semantics
///
/// - [`Receiver::try_next`] is **non-blocking**: it attempts to receive an
/// event immediately and returns:
/// - `Some(event)` if an event is available.
/// - `None` if no event can currently be received. In this crate's
/// implementations, this covers both the channel being empty and the
/// sender side being closed.
/// - [`Receiver::wait_next`] returns a future that will **asynchronously**
/// wait for and yield the next event.
pub trait Receiver<E> {
/// Attempt to receive the next event without blocking.
///
/// Returns `Some(event)` if an event is immediately available.
///
/// Returns `None` if there are no pending events. For the provided
/// `DynamicReceiver` implementation, this occurs when the underlying
/// channel is empty or the sender side has been closed.
fn try_next(&mut self) -> Option<E>;
/// Receive the next event, waiting asynchronously until one is available.

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in documentation comment: "Receiver an event" should be "Receive an event".

Suggested change
/// Receiver an event
/// Receive an event

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment /// Receiver an event has a grammatical error ("Receiver" vs "Receive"). Consider updating it to /// Receive an event for clarity and consistency with surrounding documentation.

Suggested change
/// Receiver an event
/// Receive an event

Copilot uses AI. Check for mistakes.
fn wait_next(&mut self) -> impl Future<Output = E>;
}

impl<E> Sender<E> for DynamicSender<'_, E> {
fn try_send(&mut self, event: E) -> Option<()> {
DynamicSender::try_send(self, event).ok()
}

fn send(&mut self, event: E) -> impl Future<Output = ()> {
DynamicSender::send(self, event)
}
}

impl<E> Receiver<E> for DynamicReceiver<'_, E> {
fn try_next(&mut self) -> Option<E> {
self.try_receive().ok()
}

fn wait_next(&mut self) -> impl Future<Output = E> {
self.receive()
}
}
1 change: 1 addition & 0 deletions embedded-service/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub mod buffer;
pub mod cfu;
pub mod comms;
pub mod ec_type;
pub mod event;
pub mod fmt;
pub mod hid;
pub mod init;
Expand Down
Loading
Loading