diff --git a/Cargo.lock b/Cargo.lock index 75d1f705..c404b4f5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -160,7 +160,6 @@ name = "battery-service" version = "0.1.0" dependencies = [ "defmt 0.3.100", - "embassy-executor", "embassy-futures", "embassy-sync", "embassy-time", @@ -333,7 +332,6 @@ name = "cfu-service" version = "0.1.0" dependencies = [ "defmt 0.3.100", - "embassy-executor", "embassy-futures", "embassy-sync", "embassy-time", @@ -437,41 +435,6 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" -[[package]] -name = "darling" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.106", -] - -[[package]] -name = "darling_macro" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.106", -] - [[package]] name = "dd-manifest-tree" version = "1.0.0" @@ -488,7 +451,6 @@ dependencies = [ "bbq2", "critical-section", "defmt 0.3.100", - "embassy-executor", "embassy-sync", "embassy-time", "embedded-services", @@ -611,33 +573,6 @@ dependencies = [ "nb 1.1.0", ] -[[package]] -name = "embassy-executor" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06070468370195e0e86f241c8e5004356d696590a678d47d6676795b2e439c6b" -dependencies = [ - "cortex-m", - "critical-section", - "defmt 1.0.1", - "document-features", - "embassy-executor-macros", - "embassy-executor-timer-queue", - "log", -] - -[[package]] -name = "embassy-executor-macros" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfdddc3a04226828316bf31393b6903ee162238576b1584ee2669af215d55472" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 2.0.106", -] - [[package]] name = "embassy-executor-timer-queue" version = "0.1.0" @@ -992,7 +927,6 @@ dependencies = [ "cortex-m", "cortex-m-rt", "defmt 0.3.100", - "embassy-executor", "embassy-futures", "embassy-imxrt", "embassy-sync", @@ -1014,12 +948,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - [[package]] name = "funty" version = "2.0.0" @@ -1136,12 +1064,6 @@ dependencies = [ "log", ] -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - [[package]] name = "include_dir" version = "0.7.4" @@ -1256,7 +1178,6 @@ version = "0.1.0" dependencies = [ "bitflags 2.9.4", "defmt 0.3.100", - "embassy-executor", "embassy-futures", "embassy-sync", "embassy-time", @@ -1681,7 +1602,6 @@ name = "power-policy-service" version = "0.1.0" dependencies = [ "defmt 0.3.100", - "embassy-executor", "embassy-futures", "embassy-sync", "embassy-time", @@ -2010,12 +1930,6 @@ name = "storage_bus" version = "0.1.0" source = "git+https://github.com/OpenDevicePartnership/embedded-mcu#458f99699831ef5fbb557175334195cca7440f49" -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - [[package]] name = "subenum" version = "1.1.2" @@ -2061,7 +1975,6 @@ name = "thermal-service" version = "0.1.0" dependencies = [ "defmt 0.3.100", - "embassy-executor", "embassy-futures", "embassy-sync", "embassy-time", @@ -2275,7 +2188,6 @@ dependencies = [ "bitflags 2.9.4", "critical-section", "defmt 0.3.100", - "embassy-executor", "embassy-futures", "embassy-sync", "embassy-time", diff --git a/Cargo.toml b/Cargo.toml index 898fb9ca..b0f7823a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,6 @@ cortex-m-rt = "0.7.5" critical-section = "1.1" defmt = "0.3" document-features = "0.2.7" -embassy-executor = "0.9.1" embassy-futures = "0.1.2" embassy-imxrt = { git = "https://github.com/OpenDevicePartnership/embassy-imxrt" } embassy-sync = "0.7.2" @@ -69,7 +68,7 @@ postcard = "1.*" proc-macro2 = "1.0" quote = "1.0" rand_core = "0.6.4" -rstest = {version = "0.26.1", default-features = false } +rstest = { version = "0.26.1", default-features = false } serde = { version = "1.0.*", default-features = false } static_cell = "2.1.0" toml = { version = "0.8", default-features = false } diff --git a/battery-service/Cargo.toml b/battery-service/Cargo.toml index 04e3a478..44d718bf 100644 --- a/battery-service/Cargo.toml +++ b/battery-service/Cargo.toml @@ -12,7 +12,6 @@ workspace = true [dependencies] defmt = { workspace = true, optional = true } -embassy-executor.workspace = true embassy-futures.workspace = true embassy-sync.workspace = true embassy-time.workspace = true @@ -31,7 +30,6 @@ defmt = [ "embedded-services/defmt", "embassy-time/defmt", "embassy-sync/defmt", - "embassy-executor/defmt", "embedded-batteries-async/defmt", "mctp-rs/defmt", ] @@ -40,5 +38,4 @@ log = [ "embedded-services/log", "embassy-time/log", "embassy-sync/log", - "embassy-executor/log", ] diff --git a/battery-service/src/lib.rs b/battery-service/src/lib.rs index c0a83947..c6554076 100644 --- a/battery-service/src/lib.rs +++ b/battery-service/src/lib.rs @@ -7,13 +7,14 @@ use embassy_futures::select::select; use embedded_services::{ comms::{self, EndpointID}, ec_type::message::StdHostRequest, - error, info, trace, + trace, }; mod acpi; pub mod context; pub mod controller; pub mod device; +pub mod task; pub mod wrapper; /// Standard Battery Service. @@ -134,18 +135,3 @@ pub async fn wait_for_battery_response() -> context::BatteryResponse { pub async fn get_state() -> context::State { SERVICE.context.get_state().await } - -/// Battery service task. -#[embassy_executor::task] -pub async fn task() { - info!("Starting battery-service task"); - - if comms::register_endpoint(&SERVICE, &SERVICE.endpoint).await.is_err() { - error!("Failed to register battery service endpoint"); - return; - } - - loop { - SERVICE.process_next().await; - } -} diff --git a/battery-service/src/task.rs b/battery-service/src/task.rs new file mode 100644 index 00000000..9e63bc3b --- /dev/null +++ b/battery-service/src/task.rs @@ -0,0 +1,17 @@ +use embedded_services::{comms, error, info}; + +use crate::SERVICE; + +/// Battery service task. +pub async fn task() { + info!("Starting battery-service task"); + + if comms::register_endpoint(&SERVICE, &SERVICE.endpoint).await.is_err() { + error!("Failed to register battery service endpoint"); + return; + } + + loop { + SERVICE.process_next().await; + } +} diff --git a/cfu-service/Cargo.toml b/cfu-service/Cargo.toml index 84c71afa..09cec4ff 100644 --- a/cfu-service/Cargo.toml +++ b/cfu-service/Cargo.toml @@ -9,7 +9,6 @@ workspace = true [dependencies] defmt = { workspace = true, optional = true } -embassy-executor.workspace = true embassy-futures.workspace = true embassy-sync.workspace = true embassy-time.workspace = true @@ -25,7 +24,6 @@ defmt = [ "embedded-services/defmt", "embassy-time/defmt", "embassy-sync/defmt", - "embassy-executor/defmt", "embedded-cfu-protocol/defmt", ] log = [ @@ -33,6 +31,5 @@ log = [ "embedded-services/log", "embassy-time/log", "embassy-sync/log", - "embassy-executor/log", "embedded-cfu-protocol/log", ] diff --git a/cfu-service/src/lib.rs b/cfu-service/src/lib.rs index 9d4c1962..9e6b4948 100644 --- a/cfu-service/src/lib.rs +++ b/cfu-service/src/lib.rs @@ -1,6 +1,5 @@ #![no_std] -use embassy_sync::once_lock::OnceLock; use embedded_cfu_protocol::client::CfuReceiveContent; use embedded_cfu_protocol::components::CfuComponentTraits; use embedded_cfu_protocol::protocol_definitions::*; @@ -11,6 +10,7 @@ use embedded_services::{comms, error, info, trace}; pub mod buffer; pub mod host; pub mod splitter; +pub mod task; pub struct CfuClient { /// Cfu Client context @@ -110,21 +110,3 @@ impl CfuClient { } impl comms::MailboxDelegate for CfuClient {} - -#[embassy_executor::task] -pub async fn task() { - info!("Starting cfu client task"); - static CLIENT: OnceLock = OnceLock::new(); - let cfuclient = CLIENT.get_or_init(|| CfuClient::create().expect("cfu client singleton already initialized")); - - if comms::register_endpoint(cfuclient, &cfuclient.tp).await.is_err() { - error!("Failed to register cfu endpoint"); - return; - } - - loop { - if let Err(e) = cfuclient.process_request().await { - error!("Error processing request: {:?}", e); - } - } -} diff --git a/cfu-service/src/task.rs b/cfu-service/src/task.rs new file mode 100644 index 00000000..1bade1e1 --- /dev/null +++ b/cfu-service/src/task.rs @@ -0,0 +1,21 @@ +use embassy_sync::once_lock::OnceLock; +use embedded_services::{comms, error, info}; + +use crate::CfuClient; + +pub async fn task() { + info!("Starting cfu client task"); + static CLIENT: OnceLock = OnceLock::new(); + let cfuclient = CLIENT.get_or_init(|| CfuClient::create().expect("cfu client singleton already initialized")); + + if comms::register_endpoint(cfuclient, &cfuclient.tp).await.is_err() { + error!("Failed to register cfu endpoint"); + return; + } + + loop { + if let Err(e) = cfuclient.process_request().await { + error!("Error processing request: {:?}", e); + } + } +} diff --git a/debug-service/Cargo.toml b/debug-service/Cargo.toml index d6cb04ae..799499ca 100644 --- a/debug-service/Cargo.toml +++ b/debug-service/Cargo.toml @@ -9,7 +9,6 @@ repository.workspace = true bbq2 = "0.4.2" critical-section.workspace = true defmt.workspace = true -embassy-executor.workspace = true embassy-sync.workspace = true embassy-time.workspace = true embedded-services.workspace = true diff --git a/debug-service/src/debug_service.rs b/debug-service/src/debug_service.rs index d9dadffe..134fed49 100644 --- a/debug-service/src/debug_service.rs +++ b/debug-service/src/debug_service.rs @@ -134,7 +134,7 @@ pub async fn host_endpoint_id() -> EndpointID { /// - Idempotent: repeated or concurrent calls return the same global instance. /// - Panics if endpoint registration fails (e.g. duplicate registration). /// -/// The typical caller is the Embassy task [`debug_service`]. +/// The typical caller is the task [`crate::task::debug_service`]. /// /// # Example /// ```no_run @@ -153,8 +153,3 @@ pub async fn debug_service_entry(endpoint: comms::Endpoint) { // Emit an initial defmt frame so the defmt_to_host_task can drain and verify the path. debug!("debug service initialized and endpoint registered"); } - -#[embassy_executor::task] -pub async fn debug_service(endpoint: comms::Endpoint) { - debug_service_entry(endpoint).await; -} diff --git a/debug-service/src/defmt_ring_logger.rs b/debug-service/src/defmt_ring_logger.rs index 1b9e7bd2..3ff81889 100644 --- a/debug-service/src/defmt_ring_logger.rs +++ b/debug-service/src/defmt_ring_logger.rs @@ -3,15 +3,10 @@ use bbq2::{ queue::BBQueue, traits::{coordination::cas::AtomicCoord, notifier::maitake::MaiNotSpsc, storage::Inline}, }; -use core::borrow::Borrow; use core::{ - borrow::BorrowMut, ops::DerefMut, sync::atomic::{AtomicBool, Ordering}, }; -use embedded_services::ec_type::message::{StdHostPayload, StdHostRequest}; - -use crate::{frame_available, shared_buffer}; static RTT_INITIALIZED: AtomicBool = AtomicBool::new(false); static mut ENCODER: defmt::Encoder = defmt::Encoder::new(); @@ -19,7 +14,7 @@ static mut RESTORE_STATE: critical_section::RestoreState = critical_section::Res type Queue = BBQueue, AtomicCoord, MaiNotSpsc>; -static DEFMT_BUFFER: Queue = Queue::new(); +pub(crate) static DEFMT_BUFFER: Queue = Queue::new(); static mut WRITE_GRANT: Option> = None; static mut WRITTEN: usize = 0; @@ -167,115 +162,3 @@ unsafe fn write(bytes: &[u8]) { rtt_bytes = &rtt_bytes[written..]; } } - -#[embassy_executor::task] -pub async fn defmt_to_host_task() { - embedded_services::info!("defmt to host task start"); - use crate::debug_service::{host_endpoint_id, response_notify_signal}; - use embedded_services::comms::{self, EndpointID, Internal}; - use embedded_services::ec_type::message::HostMsg; - - let framed_consumer = DEFMT_BUFFER.framed_consumer(); - - let host_ep = host_endpoint_id().await; - - // Acquire the staging buffer once; we own it for the task lifetime. - let acpi_owned = crate::owned_buffer(); - - loop { - // Wait for a complete defmt frame to be available (do not release yet) - let frame = framed_consumer.wait_read().await; - - // Copy frame bytes into the static ACPI buffer. - // Producer commits frames atomically with size ≤ DEFMT_MAX_BYTES (1024), - // so the consumer never sees a partial frame. We still clamp to the - // destination length to be robust if the staging buffer size changes. - let copy_len = core::cmp::min(frame.len(), acpi_owned.len()); - { - let mut access = acpi_owned.borrow_mut(); - let buf: &mut [u8] = BorrowMut::borrow_mut(&mut access); - - buf[..copy_len].copy_from_slice(&frame[..copy_len]); - } - - frame.release(); - embedded_services::trace!("released defmt frame (staged {} bytes)", copy_len); - - // Notify the host that data is available - // No notification for now until that's sorted. Host will periodically poll - // TODO: Revisit once host notifications are stabilized. - /*let _ = comms::send( - EndpointID::Internal(Internal::Debug), - host_ep, - &HostMsg::Notification(NotificationMsg { offset: 20 }), - ) - .await;*/ - - // Wait for host notification/ack via the debug service - frame_available(true); - let _n = response_notify_signal().wait().await; - frame_available(false); - embedded_services::trace!("host ack received, sending defmt response"); - - // Send the staged defmt bytes frame as an ACPI-style message. - // Scope the message so the shared borrow is dropped before we clear the buffer. - { - let msg = HostMsg::Response(StdHostRequest { - command: embedded_services::ec_type::message::OdpCommand::Debug( - embedded_services::ec_type::protocols::debug::DebugCmd::GetMsgs, - ), - status: 0, - payload: StdHostPayload::DebugGetMsgsResponse { - debug_buf: { - let access = shared_buffer().borrow(); - let slice: &[u8] = access.borrow(); - slice.try_into().unwrap() - }, - }, - }); - let _ = comms::send(EndpointID::Internal(Internal::Debug), host_ep, &msg).await; - embedded_services::trace!("sent {} defmt bytes to host", copy_len); - } - - // Clear the staged portion of the buffer - { - let mut access = acpi_owned.borrow_mut(); - let buf: &mut [u8] = BorrowMut::borrow_mut(&mut access); - buf[..copy_len].fill(0); - } - } -} - -#[embassy_executor::task] -pub async fn no_avail_to_host_task() { - embedded_services::define_static_buffer!(no_avail_acpi_buf, u8, [0u8; 12]); - - embedded_services::info!("no avail to host task start"); - use crate::debug_service::{host_endpoint_id, no_avail_notify_signal}; - use embedded_services::comms::{self, EndpointID, Internal}; - use embedded_services::ec_type::message::HostMsg; - - let host_ep = host_endpoint_id().await; - - let acpi_owned = no_avail_acpi_buf::get_mut().expect("defmt staging buffer already initialized elsewhere"); - { - let mut access = acpi_owned.borrow_mut(); - let buf: &mut [u8] = BorrowMut::borrow_mut(&mut access); - // Use 0xDEADBEEF to signify no frame available - buf[4..12].copy_from_slice(&0xDEADBEEFu64.to_be_bytes()); - } - - let msg = HostMsg::Response(StdHostRequest { - command: embedded_services::ec_type::message::OdpCommand::Debug( - embedded_services::ec_type::protocols::debug::DebugCmd::GetMsgs, - ), - status: 1, - payload: StdHostPayload::ErrorResponse {}, - }); - - // Send DEADBEEF if host requests frame but non available - loop { - no_avail_notify_signal().wait().await; - let _ = comms::send(EndpointID::Internal(Internal::Debug), host_ep, &msg).await; - } -} diff --git a/debug-service/src/lib.rs b/debug-service/src/lib.rs index 07e4b4f3..f30f73e0 100644 --- a/debug-service/src/lib.rs +++ b/debug-service/src/lib.rs @@ -1,6 +1,6 @@ #![no_std] mod debug_service; mod defmt_ring_logger; +pub mod task; pub use debug_service::*; -pub use defmt_ring_logger::{defmt_to_host_task, no_avail_to_host_task}; diff --git a/debug-service/src/task.rs b/debug-service/src/task.rs new file mode 100644 index 00000000..d88f8592 --- /dev/null +++ b/debug-service/src/task.rs @@ -0,0 +1,122 @@ +use core::borrow::{Borrow, BorrowMut}; + +use embedded_services::{ + comms, + ec_type::message::{StdHostPayload, StdHostRequest}, +}; + +use crate::{debug_service_entry, defmt_ring_logger::DEFMT_BUFFER, frame_available, shared_buffer}; + +pub async fn debug_service(endpoint: comms::Endpoint) { + debug_service_entry(endpoint).await; +} + +pub async fn defmt_to_host_task() { + embedded_services::info!("defmt to host task start"); + use crate::debug_service::{host_endpoint_id, response_notify_signal}; + use embedded_services::comms::{self, EndpointID, Internal}; + use embedded_services::ec_type::message::HostMsg; + + let framed_consumer = DEFMT_BUFFER.framed_consumer(); + + let host_ep = host_endpoint_id().await; + + // Acquire the staging buffer once; we own it for the task lifetime. + let acpi_owned = crate::owned_buffer(); + + loop { + // Wait for a complete defmt frame to be available (do not release yet) + let frame = framed_consumer.wait_read().await; + + // Copy frame bytes into the static ACPI buffer. + // Producer commits frames atomically with size ≤ DEFMT_MAX_BYTES (1024), + // so the consumer never sees a partial frame. We still clamp to the + // destination length to be robust if the staging buffer size changes. + let copy_len = core::cmp::min(frame.len(), acpi_owned.len()); + { + let mut access = acpi_owned.borrow_mut(); + let buf: &mut [u8] = BorrowMut::borrow_mut(&mut access); + + buf[..copy_len].copy_from_slice(&frame[..copy_len]); + } + + frame.release(); + embedded_services::trace!("released defmt frame (staged {} bytes)", copy_len); + + // Notify the host that data is available + // No notification for now until that's sorted. Host will periodically poll + // TODO: Revisit once host notifications are stabilized. + /*let _ = comms::send( + EndpointID::Internal(Internal::Debug), + host_ep, + &HostMsg::Notification(NotificationMsg { offset: 20 }), + ) + .await;*/ + + // Wait for host notification/ack via the debug service + frame_available(true); + let _n = response_notify_signal().wait().await; + frame_available(false); + embedded_services::trace!("host ack received, sending defmt response"); + + // Send the staged defmt bytes frame as an ACPI-style message. + // Scope the message so the shared borrow is dropped before we clear the buffer. + { + let msg = HostMsg::Response(StdHostRequest { + command: embedded_services::ec_type::message::OdpCommand::Debug( + embedded_services::ec_type::protocols::debug::DebugCmd::GetMsgs, + ), + status: 0, + payload: StdHostPayload::DebugGetMsgsResponse { + debug_buf: { + let access = shared_buffer().borrow(); + let slice: &[u8] = access.borrow(); + slice.try_into().unwrap() + }, + }, + }); + let _ = comms::send(EndpointID::Internal(Internal::Debug), host_ep, &msg).await; + embedded_services::trace!("sent {} defmt bytes to host", copy_len); + } + + // Clear the staged portion of the buffer + { + let mut access = acpi_owned.borrow_mut(); + let buf: &mut [u8] = BorrowMut::borrow_mut(&mut access); + buf[..copy_len].fill(0); + } + } +} + +pub async fn no_avail_to_host_task() { + embedded_services::define_static_buffer!(no_avail_acpi_buf, u8, [0u8; 12]); + + embedded_services::info!("no avail to host task start"); + use crate::debug_service::{host_endpoint_id, no_avail_notify_signal}; + use embedded_services::comms::{self, EndpointID, Internal}; + use embedded_services::ec_type::message::HostMsg; + + let host_ep = host_endpoint_id().await; + + let acpi_owned = no_avail_acpi_buf::get_mut().expect("defmt staging buffer already initialized elsewhere"); + { + let mut access = acpi_owned.borrow_mut(); + let buf: &mut [u8] = BorrowMut::borrow_mut(&mut access); + // Use 0xDEADBEEF to signify no frame available + buf[4..12].copy_from_slice(&0xDEADBEEFu64.to_be_bytes()); + } + + let msg = HostMsg::Response(StdHostRequest { + command: embedded_services::ec_type::message::OdpCommand::Debug( + embedded_services::ec_type::protocols::debug::DebugCmd::GetMsgs, + ), + status: 1, + payload: StdHostPayload::ErrorResponse {}, + }); + + // Send DEADBEEF if host requests frame but non available + loop { + no_avail_notify_signal().wait().await; + let _ = comms::send(EndpointID::Internal(Internal::Debug), host_ep, &msg).await; + } +} diff --git a/embedded-service/src/hid/mod.rs b/embedded-service/src/hid/mod.rs index 2631998f..b637262a 100644 --- a/embedded-service/src/hid/mod.rs +++ b/embedded-service/src/hid/mod.rs @@ -2,7 +2,6 @@ //! See spec at use core::convert::Infallible; -use embassy_sync::once_lock::OnceLock; use embassy_sync::signal::Signal; use crate::buffer::SharedRef; @@ -290,30 +289,25 @@ struct Context { } impl Context { - fn new() -> Self { + const fn new() -> Self { Context { devices: IntrusiveList::new(), } } } -static CONTEXT: OnceLock = OnceLock::new(); - -/// Init HID service -pub fn init() { - CONTEXT.get_or_init(Context::new); -} +static CONTEXT: Context = Context::new(); /// Register a device with the HID service pub async fn register_device(device: &'static impl DeviceContainer) -> Result<(), intrusive_list::Error> { let device = device.get_hid_device(); - CONTEXT.get().await.devices.push(device)?; + CONTEXT.devices.push(device)?; comms::register_endpoint(device, &device.tp).await } /// Find a device by its ID -pub async fn get_device(id: DeviceId) -> Option<&'static Device> { - for device in &CONTEXT.get().await.devices { +pub fn get_device(id: DeviceId) -> Option<&'static Device> { + for device in &CONTEXT.devices { if let Some(data) = device.data::() { if data.id == id { return Some(data); diff --git a/embedded-service/src/lib.rs b/embedded-service/src/lib.rs index ddf245eb..d4bee102 100644 --- a/embedded-service/src/lib.rs +++ b/embedded-service/src/lib.rs @@ -67,7 +67,6 @@ pub type SyncCell = thread_mode_cell::ThreadModeCell; pub async fn init() { comms::init(); activity::init(); - hid::init(); cfu::init(); keyboard::init(); power::policy::init(); diff --git a/espi-service/Cargo.toml b/espi-service/Cargo.toml index c06b149f..0734a57e 100644 --- a/espi-service/Cargo.toml +++ b/espi-service/Cargo.toml @@ -17,16 +17,10 @@ log = { workspace = true, optional = true } embassy-time.workspace = true embassy-sync.workspace = true embassy-imxrt = { workspace = true, features = ["mimxrt633s"] } -embassy-executor.workspace = true embassy-futures.workspace = true mctp-rs = { workspace = true, features = ["espi"] } [target.'cfg(target_os = "none")'.dependencies] -embassy-executor = { workspace = true, features = [ - "executor-thread", - "executor-interrupt", - "arch-cortex-m", -] } cortex-m-rt.workspace = true cortex-m = { workspace = true, features = [ "inline-asm", @@ -47,7 +41,6 @@ defmt = [ "embassy-time/defmt-timestamp-uptime", "embassy-sync/defmt", "embassy-imxrt/defmt", - "embassy-executor/defmt", "mctp-rs/defmt", ] diff --git a/espi-service/src/espi_service.rs b/espi-service/src/espi_service.rs index 508695ca..53721341 100644 --- a/espi-service/src/espi_service.rs +++ b/espi-service/src/espi_service.rs @@ -2,7 +2,7 @@ use core::mem::offset_of; use core::slice; use core::borrow::BorrowMut; -use embassy_futures::select::select; +use embassy_imxrt::espi; use embassy_sync::channel::Channel; use embassy_sync::mutex::Mutex; use embassy_sync::once_lock::OnceLock; @@ -146,11 +146,11 @@ impl Service<'_> { Ok(()) } - async fn wait_for_subsystem_msg(&self) -> HostMsgInternal { + pub(crate) async fn wait_for_subsystem_msg(&self) -> HostMsgInternal { self.host_tx_queue.receive().await } - async fn process_subsystem_msg(&self, espi: &mut espi::Espi<'static>, host_msg: HostMsgInternal) { + pub(crate) async fn process_subsystem_msg(&self, espi: &mut espi::Espi<'static>, host_msg: HostMsgInternal) { let (endpoint, host_msg) = host_msg; match host_msg { HostMsg::Notification(notification_msg) => self.process_notification_to_host(espi, ¬ification_msg).await, @@ -272,6 +272,10 @@ impl Service<'_> { } } } + + pub(crate) fn endpoint(&self) -> &comms::Endpoint { + &self.endpoint + } } impl comms::MailboxDelegate for Service<'_> { @@ -304,52 +308,9 @@ impl comms::MailboxDelegate for Service<'_> { } } -static ESPI_SERVICE: OnceLock = OnceLock::new(); - -use embassy_imxrt::espi; - -#[embassy_executor::task] -pub async fn espi_service(mut espi: espi::Espi<'static>, memory_map_buffer: &'static mut [u8]) { - info!("Reserved eSPI memory map buffer size: {}", memory_map_buffer.len()); - info!("eSPI MemoryMap size: {}", size_of::()); - - if size_of::() > memory_map_buffer.len() { - panic!("eSPI MemoryMap is too big for reserved memory buffer!!!"); - } - - memory_map_buffer.fill(0); - - let memory_map: &mut ec_type::structure::ECMemory = - unsafe { &mut *(memory_map_buffer.as_mut_ptr() as *mut ec_type::structure::ECMemory) }; - - espi.wait_for_plat_reset().await; - - info!("Initializing memory map"); - memory_map.ver.major = ec_type::structure::EC_MEMMAP_VERSION.major; - memory_map.ver.minor = ec_type::structure::EC_MEMMAP_VERSION.minor; - memory_map.ver.spin = ec_type::structure::EC_MEMMAP_VERSION.spin; - memory_map.ver.res0 = ec_type::structure::EC_MEMMAP_VERSION.res0; - - let espi_service = ESPI_SERVICE.get_or_init(|| Service::new(memory_map)); - comms::register_endpoint(espi_service, &espi_service.endpoint) - .await - .unwrap(); - - loop { - let event = select(espi.wait_for_event(), espi_service.wait_for_subsystem_msg()).await; - - match event { - embassy_futures::select::Either::First(controller_event) => { - process_controller_event(&mut espi, espi_service, controller_event).await - } - embassy_futures::select::Either::Second(host_msg) => { - espi_service.process_subsystem_msg(&mut espi, host_msg).await - } - } - } -} +pub(crate) static ESPI_SERVICE: OnceLock = OnceLock::new(); -async fn process_controller_event( +pub(crate) async fn process_controller_event( espi: &mut espi::Espi<'static>, espi_service: &Service<'_>, event: Result, diff --git a/espi-service/src/lib.rs b/espi-service/src/lib.rs index 39f11316..2c549385 100644 --- a/espi-service/src/lib.rs +++ b/espi-service/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] mod espi_service; +pub mod task; pub use espi_service::*; diff --git a/espi-service/src/task.rs b/espi-service/src/task.rs new file mode 100644 index 00000000..2719184c --- /dev/null +++ b/espi-service/src/task.rs @@ -0,0 +1,45 @@ +use embassy_futures::select::select; +use embassy_imxrt::espi; +use embedded_services::{comms, ec_type, info}; + +use crate::{ESPI_SERVICE, Service, process_controller_event}; + +pub async fn espi_service(mut espi: espi::Espi<'static>, memory_map_buffer: &'static mut [u8]) { + info!("Reserved eSPI memory map buffer size: {}", memory_map_buffer.len()); + info!("eSPI MemoryMap size: {}", size_of::()); + + if size_of::() > memory_map_buffer.len() { + panic!("eSPI MemoryMap is too big for reserved memory buffer!!!"); + } + + memory_map_buffer.fill(0); + + let memory_map: &mut ec_type::structure::ECMemory = + unsafe { &mut *(memory_map_buffer.as_mut_ptr() as *mut ec_type::structure::ECMemory) }; + + espi.wait_for_plat_reset().await; + + info!("Initializing memory map"); + memory_map.ver.major = ec_type::structure::EC_MEMMAP_VERSION.major; + memory_map.ver.minor = ec_type::structure::EC_MEMMAP_VERSION.minor; + memory_map.ver.spin = ec_type::structure::EC_MEMMAP_VERSION.spin; + memory_map.ver.res0 = ec_type::structure::EC_MEMMAP_VERSION.res0; + + let espi_service = ESPI_SERVICE.get_or_init(|| Service::new(memory_map)); + comms::register_endpoint(espi_service, espi_service.endpoint()) + .await + .unwrap(); + + loop { + let event = select(espi.wait_for_event(), espi_service.wait_for_subsystem_msg()).await; + + match event { + embassy_futures::select::Either::First(controller_event) => { + process_controller_event(&mut espi, espi_service, controller_event).await + } + embassy_futures::select::Either::Second(host_msg) => { + espi_service.process_subsystem_msg(&mut espi, host_msg).await + } + } + } +} diff --git a/examples/rt633/Cargo.lock b/examples/rt633/Cargo.lock index 09e8d6c8..e44ee57c 100644 --- a/examples/rt633/Cargo.lock +++ b/examples/rt633/Cargo.lock @@ -103,7 +103,6 @@ name = "battery-service" version = "0.1.0" dependencies = [ "defmt 0.3.100", - "embassy-executor", "embassy-futures", "embassy-sync", "embassy-time", @@ -797,7 +796,6 @@ dependencies = [ "cortex-m", "cortex-m-rt", "defmt 0.3.100", - "embassy-executor", "embassy-futures", "embassy-imxrt", "embassy-sync", diff --git a/examples/rt633/src/bin/espi.rs b/examples/rt633/src/bin/espi.rs index 1a16b28f..04cab046 100644 --- a/examples/rt633/src/bin/espi.rs +++ b/examples/rt633/src/bin/espi.rs @@ -96,6 +96,12 @@ unsafe extern "C" { static __end_espi_data: u8; } +#[embassy_executor::task] +async fn espi_service_task(espi: embassy_imxrt::espi::Espi<'static>, memory_map_buffer: &'static mut [u8]) -> ! { + espi_service::task::espi_service(espi, memory_map_buffer).await; + unreachable!() +} + #[embassy_executor::main] async fn main(spawner: Spawner) { let p = embassy_imxrt::init(Default::default()); @@ -148,7 +154,7 @@ async fn main(spawner: Spawner) { slice::from_raw_parts_mut(start_espi_data, espi_data_len) }; - spawner.must_spawn(espi_service::espi_service(espi, memory_map_buffer)); + spawner.must_spawn(espi_service_task(espi, memory_map_buffer)); battery_service::init().await; diff --git a/examples/rt633/src/bin/espi_battery.rs b/examples/rt633/src/bin/espi_battery.rs index d1d8b875..34fe2110 100644 --- a/examples/rt633/src/bin/espi_battery.rs +++ b/examples/rt633/src/bin/espi_battery.rs @@ -237,6 +237,18 @@ async fn wrapper_task(wrapper: Wrapper<'static, Bq40z50Controller>) { } } +#[embassy_executor::task] +async fn espi_service_task(espi: embassy_imxrt::espi::Espi<'static>, memory_map_buffer: &'static mut [u8]) -> ! { + espi_service::task::espi_service(espi, memory_map_buffer).await; + unreachable!() +} + +#[embassy_executor::task] +async fn battery_service_task() -> ! { + battery_service::task::task().await; + unreachable!() +} + #[embassy_executor::main] async fn main(spawner: Spawner) { let p = embassy_imxrt::init(Default::default()); @@ -289,7 +301,7 @@ async fn main(spawner: Spawner) { slice::from_raw_parts_mut(start_espi_data, espi_data_len) }; - spawner.must_spawn(espi_service::espi_service(espi, memory_map_buffer)); + spawner.must_spawn(espi_service_task(espi, memory_map_buffer)); let config = embassy_imxrt::i2c::master::Config { speed: embassy_imxrt::i2c::master::Speed::Standard, @@ -320,7 +332,7 @@ async fn main(spawner: Spawner) { ); spawner.must_spawn(wrapper_task(wrap)); - spawner.must_spawn(battery_service::task()); + spawner.must_spawn(battery_service_task()); battery_service::register_fuel_gauge(fg).unwrap(); diff --git a/examples/rt685s-evk/Cargo.lock b/examples/rt685s-evk/Cargo.lock index 7fcb8632..a29fc76f 100644 --- a/examples/rt685s-evk/Cargo.lock +++ b/examples/rt685s-evk/Cargo.lock @@ -1276,7 +1276,6 @@ name = "power-policy-service" version = "0.1.0" dependencies = [ "defmt 0.3.100", - "embassy-executor", "embassy-futures", "embassy-sync", "embassy-time", @@ -1589,7 +1588,6 @@ dependencies = [ "bitfield 0.17.0", "bitflags 2.9.4", "defmt 0.3.100", - "embassy-executor", "embassy-futures", "embassy-sync", "embassy-time", diff --git a/examples/rt685s-evk/src/bin/type_c.rs b/examples/rt685s-evk/src/bin/type_c.rs index 065e39b3..89dda567 100644 --- a/examples/rt685s-evk/src/bin/type_c.rs +++ b/examples/rt685s-evk/src/bin/type_c.rs @@ -64,6 +64,18 @@ async fn interrupt_task(mut int_in: Input<'static>, mut interrupt: Interrupt<'st tps6699x::task::interrupt_task(&mut int_in, &mut [&mut interrupt]).await; } +#[embassy_executor::task] +async fn type_c_service_task() -> ! { + type_c_service::task(Default::default()).await; + unreachable!() +} + +#[embassy_executor::task] +async fn power_policy_service_task() -> ! { + power_policy_service::task::task(Default::default()).await; + unreachable!() +} + #[embassy_executor::main] async fn main(spawner: Spawner) { let p = embassy_imxrt::init(Default::default()); @@ -74,10 +86,10 @@ async fn main(spawner: Spawner) { type_c::controller::init(); info!("Spawining power policy task"); - spawner.must_spawn(power_policy_service::task(Default::default())); + spawner.must_spawn(power_policy_service_task()); info!("Spawining type-c service task"); - spawner.must_spawn(type_c_service::task(Default::default())); + spawner.must_spawn(type_c_service_task()); let int_in = Input::new(p.PIO1_7, Pull::Up, Inverter::Disabled); static BUS: StaticCell>> = StaticCell::new(); diff --git a/examples/rt685s-evk/src/bin/type_c_cfu.rs b/examples/rt685s-evk/src/bin/type_c_cfu.rs index b227b4f8..342a2860 100644 --- a/examples/rt685s-evk/src/bin/type_c_cfu.rs +++ b/examples/rt685s-evk/src/bin/type_c_cfu.rs @@ -149,6 +149,18 @@ async fn fw_update_task() { info!("Got version: {:#x}", version); } +#[embassy_executor::task] +async fn type_c_service_task() -> ! { + type_c_service::task(Default::default()).await; + unreachable!() +} + +#[embassy_executor::task] +async fn power_policy_service_task() -> ! { + power_policy_service::task::task(Default::default()).await; + unreachable!() +} + #[embassy_executor::main] async fn main(spawner: Spawner) { let p = embassy_imxrt::init(Default::default()); @@ -159,10 +171,10 @@ async fn main(spawner: Spawner) { type_c::controller::init(); info!("Spawining power policy task"); - spawner.must_spawn(power_policy_service::task(Default::default())); + spawner.must_spawn(power_policy_service_task()); info!("Spawining type-c service task"); - spawner.must_spawn(type_c_service::task(Default::default())); + spawner.must_spawn(type_c_service_task()); let int_in = Input::new(p.PIO1_7, Pull::Up, Inverter::Disabled); static BUS: StaticCell>> = StaticCell::new(); diff --git a/examples/std/Cargo.lock b/examples/std/Cargo.lock index 1b0a3cad..421afb73 100644 --- a/examples/std/Cargo.lock +++ b/examples/std/Cargo.lock @@ -116,7 +116,6 @@ dependencies = [ name = "battery-service" version = "0.1.0" dependencies = [ - "embassy-executor", "embassy-futures", "embassy-sync", "embassy-time", @@ -268,7 +267,6 @@ checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" name = "cfu-service" version = "0.1.0" dependencies = [ - "embassy-executor", "embassy-futures", "embassy-sync", "embassy-time", @@ -392,7 +390,6 @@ dependencies = [ "bbq2", "critical-section", "defmt 0.3.100", - "embassy-executor", "embassy-sync", "embassy-time", "embedded-services", @@ -1284,7 +1281,6 @@ checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" name = "power-policy-service" version = "0.1.0" dependencies = [ - "embassy-executor", "embassy-futures", "embassy-sync", "embassy-time", @@ -1600,7 +1596,6 @@ dependencies = [ name = "thermal-service" version = "0.1.0" dependencies = [ - "embassy-executor", "embassy-futures", "embassy-sync", "embassy-time", @@ -1750,7 +1745,6 @@ version = "0.1.0" dependencies = [ "bitfield 0.17.0", "bitflags 2.9.4", - "embassy-executor", "embassy-futures", "embassy-sync", "embassy-time", diff --git a/examples/std/src/bin/battery.rs b/examples/std/src/bin/battery.rs index 79e90ee8..4ff2430f 100644 --- a/examples/std/src/bin/battery.rs +++ b/examples/std/src/bin/battery.rs @@ -3,7 +3,7 @@ use std::convert::Infallible; use battery_service::controller::{Controller, ControllerEvent}; use battery_service::device::{Device, DeviceId, DynamicBatteryMsgs, StaticBatteryMsgs}; use battery_service::wrapper::Wrapper; -use embassy_executor::{Executor, Spawner}; +use embassy_executor::Spawner; use embassy_sync::once_lock::OnceLock; use embassy_time::{Duration, Timer}; use embedded_batteries_async::charger::{MilliAmps, MilliVolts}; @@ -13,7 +13,6 @@ use embedded_batteries_async::smart_battery::{ }; use embedded_hal_mock::eh1::i2c::Mock; use embedded_services::info; -use static_cell::StaticCell; mod espi_service { use battery_service::context::{BatteryEvent, BatteryEventInner}; @@ -93,6 +92,18 @@ mod espi_service { } Timer::after_secs(5).await; + espi_service + .endpoint + .send( + EndpointID::Internal(comms::Internal::Battery), + &BatteryEvent { + device_id: DeviceId(0), + event: BatteryEventInner::PollStaticData, + }, + ) + .await + .unwrap(); + loop { espi_service .endpoint @@ -266,7 +277,7 @@ impl Controller for FuelGaugeController { } fn get_timeout(&self) -> Duration { - unimplemented!() + Duration::from_secs(5) } fn set_timeout(&mut self, _duration: Duration) { @@ -450,19 +461,6 @@ impl embedded_batteries_async::smart_battery: } } -#[embassy_executor::task] -async fn init_task(spawner: Spawner, dev: &'static Device) { - embedded_services::init().await; - info!("services init'd"); - - espi_service::init().await; - info!("espi service init'd"); - - battery_service::register_fuel_gauge(dev).unwrap(); - - spawner.must_spawn(espi_service::task()); -} - #[embassy_executor::task] async fn wrapper_task(wrapper: Wrapper<'static, FuelGaugeController>) { loop { @@ -471,11 +469,15 @@ async fn wrapper_task(wrapper: Wrapper<'static, FuelGaugeController>) { } } -fn main() { - env_logger::builder().filter_level(log::LevelFilter::Trace).init(); +#[embassy_executor::task] +async fn battery_service_task() -> ! { + battery_service::task::task().await; + unreachable!() +} - static EXECUTOR: StaticCell = StaticCell::new(); - let executor = EXECUTOR.init(Executor::new()); +#[embassy_executor::main] +async fn main(spawner: Spawner) { + env_logger::builder().filter_level(log::LevelFilter::Trace).init(); let expectations = vec![]; @@ -489,9 +491,16 @@ fn main() { driver: MockFuelGaugeDriver::new(Mock::new(&expectations)), }, ); - executor.run(|spawner| { - spawner.must_spawn(wrapper_task(wrap)); - spawner.must_spawn(battery_service::task()); - spawner.must_spawn(init_task(spawner, dev)); - }); + + embedded_services::init().await; + info!("services init'd"); + + espi_service::init().await; + info!("espi service init'd"); + + battery_service::register_fuel_gauge(dev).unwrap(); + + spawner.must_spawn(espi_service::task()); + spawner.must_spawn(wrapper_task(wrap)); + spawner.must_spawn(battery_service_task()); } diff --git a/examples/std/src/bin/cfu_buffer.rs b/examples/std/src/bin/cfu_buffer.rs index a1501841..c2c546b5 100644 --- a/examples/std/src/bin/cfu_buffer.rs +++ b/examples/std/src/bin/cfu_buffer.rs @@ -245,12 +245,18 @@ async fn run(spawner: Spawner) { info!("data: {}", size_of::()); } +#[embassy_executor::task] +async fn cfu_service_task() -> ! { + cfu_service::task::task().await; + unreachable!() +} + fn main() { env_logger::builder().filter_level(log::LevelFilter::Trace).init(); static EXECUTOR: StaticCell = StaticCell::new(); let executor = EXECUTOR.init(Executor::new()); executor.run(|spawner| { - spawner.must_spawn(cfu_service::task()); + spawner.must_spawn(cfu_service_task()); spawner.must_spawn(run(spawner)); }); } diff --git a/examples/std/src/bin/cfu_client.rs b/examples/std/src/bin/cfu_client.rs index ae7409cb..1a7a4a9b 100644 --- a/examples/std/src/bin/cfu_client.rs +++ b/examples/std/src/bin/cfu_client.rs @@ -90,13 +90,19 @@ async fn run(spawner: Spawner) { } } +#[embassy_executor::task] +async fn cfu_service_task() -> ! { + cfu_service::task::task().await; + unreachable!() +} + fn main() { env_logger::builder().filter_level(log::LevelFilter::Info).init(); static EXECUTOR: StaticCell = StaticCell::new(); let executor = EXECUTOR.init(Executor::new()); executor.run(|spawner| { - spawner.must_spawn(cfu_service::task()); + spawner.must_spawn(cfu_service_task()); spawner.must_spawn(run(spawner)); }); } diff --git a/examples/std/src/bin/cfu_splitter.rs b/examples/std/src/bin/cfu_splitter.rs index 03de66f9..b7122dac 100644 --- a/examples/std/src/bin/cfu_splitter.rs +++ b/examples/std/src/bin/cfu_splitter.rs @@ -262,13 +262,19 @@ async fn run(spawner: Spawner) { info!("Got response: {response:?}"); } +#[embassy_executor::task] +async fn cfu_service_task() -> ! { + cfu_service::task::task().await; + unreachable!() +} + fn main() { env_logger::builder().filter_level(log::LevelFilter::Info).init(); static EXECUTOR: StaticCell = StaticCell::new(); let executor = EXECUTOR.init(Executor::new()); executor.run(|spawner| { - spawner.must_spawn(cfu_service::task()); + spawner.must_spawn(cfu_service_task()); spawner.must_spawn(run(spawner)); }); } diff --git a/examples/std/src/bin/debug.rs b/examples/std/src/bin/debug.rs index da1dab4b..2d234bc6 100644 --- a/examples/std/src/bin/debug.rs +++ b/examples/std/src/bin/debug.rs @@ -1,5 +1,4 @@ /// This example is supposed to init a debug service and a mock eSPI service to demonstrate sending defmt messages from the debug service to the eSPI service -use debug_service::debug_service; use embassy_executor::{Executor, Spawner}; use embedded_services::comms::{Endpoint, EndpointID, External}; use embedded_services::info; @@ -179,14 +178,26 @@ async fn init_task(spawner: Spawner) { spawner.must_spawn(espi_service::request_task()); info!("spawn debug service"); - spawner.must_spawn(debug_service(Endpoint::uninit(EndpointID::External(External::Host)))); + spawner.must_spawn(debug_service()); info!("spawn defmt_to_host_task"); - spawner.must_spawn(debug_service::defmt_to_host_task()); + spawner.must_spawn(defmt_to_host_task()); spawner.must_spawn(defmt_frames_task()); } +#[embassy_executor::task] +async fn debug_service() -> ! { + debug_service::task::debug_service(Endpoint::uninit(EndpointID::External(External::Host))).await; + unreachable!() +} + +#[embassy_executor::task] +async fn defmt_to_host_task() -> ! { + debug_service::task::defmt_to_host_task().await; + unreachable!() +} + fn main() { env_logger::builder().filter_level(log::LevelFilter::Trace).init(); diff --git a/examples/std/src/bin/power_policy.rs b/examples/std/src/bin/power_policy.rs index bddf076e..6a1221f8 100644 --- a/examples/std/src/bin/power_policy.rs +++ b/examples/std/src/bin/power_policy.rs @@ -234,15 +234,19 @@ async fn receiver_task() { } } +#[embassy_executor::task] +async fn power_policy_task(config: power_policy_service::config::Config) -> ! { + power_policy_service::task::task(config).await; + unreachable!() +} + fn main() { env_logger::builder().filter_level(log::LevelFilter::Trace).init(); static EXECUTOR: StaticCell = StaticCell::new(); let executor = EXECUTOR.init(Executor::new()); executor.run(|spawner| { - spawner.must_spawn(power_policy_service::task( - power_policy_service::config::Config::default(), - )); + spawner.must_spawn(power_policy_task(power_policy_service::config::Config::default())); spawner.must_spawn(run(spawner)); spawner.must_spawn(receiver_task()); }); diff --git a/examples/std/src/bin/thermal.rs b/examples/std/src/bin/thermal.rs index 182b43e6..0cc765cc 100644 --- a/examples/std/src/bin/thermal.rs +++ b/examples/std/src/bin/thermal.rs @@ -343,13 +343,19 @@ async fn handle_alerts() { } } +#[embassy_executor::task] +async fn handle_requests() -> ! { + ts::task::handle_requests().await; + unreachable!() +} + #[embassy_executor::task] async fn run(spawner: Spawner) { embedded_services::init().await; init_thermal(spawner).await; spawner.must_spawn(host()); spawner.must_spawn(handle_alerts()); - spawner.must_spawn(ts::mptf::handle_requests()); + spawner.must_spawn(handle_requests()); } fn main() { @@ -362,5 +368,14 @@ fn main() { }); } -ts::impl_sensor_task!(mock_sensor_task, MockSensor, 16); -ts::impl_fan_task!(mock_fan_task, MockFan, 16); +#[embassy_executor::task] +async fn mock_sensor_task(sensor: &'static ts::sensor::Sensor) -> ! { + ts::task::sensor_task(sensor).await; + unreachable!() +} + +#[embassy_executor::task] +async fn mock_fan_task(fan: &'static ts::fan::Fan) -> ! { + ts::task::fan_task(fan).await; + unreachable!() +} diff --git a/examples/std/src/bin/type_c/external.rs b/examples/std/src/bin/type_c/external.rs index e8ea4a22..127e0b41 100644 --- a/examples/std/src/bin/type_c/external.rs +++ b/examples/std/src/bin/type_c/external.rs @@ -93,13 +93,19 @@ async fn task(_spawner: Spawner) { external::reconfigure_retimer(GlobalPortId(0)).await.unwrap(); } +#[embassy_executor::task] +async fn type_c_service_task() -> ! { + type_c_service::task(Default::default()).await; + unreachable!() +} + fn main() { env_logger::builder().filter_level(log::LevelFilter::Trace).init(); static EXECUTOR: StaticCell = StaticCell::new(); let executor = EXECUTOR.init(Executor::new()); executor.run(|spawner| { - spawner.must_spawn(type_c_service::task(Default::default())); + spawner.must_spawn(type_c_service_task()); spawner.must_spawn(task(spawner)); spawner.must_spawn(controller_task()); }); diff --git a/examples/std/src/bin/type_c/service.rs b/examples/std/src/bin/type_c/service.rs index 8e2a5013..7a2273df 100644 --- a/examples/std/src/bin/type_c/service.rs +++ b/examples/std/src/bin/type_c/service.rs @@ -144,14 +144,26 @@ async fn task(spawner: Spawner) { Timer::after_millis(DELAY_MS).await; } +#[embassy_executor::task] +async fn type_c_service_task() -> ! { + type_c_service::task(Default::default()).await; + unreachable!() +} + +#[embassy_executor::task] +async fn power_policy_service_task() -> ! { + power_policy_service::task::task(Default::default()).await; + unreachable!() +} + fn main() { env_logger::builder().filter_level(log::LevelFilter::Trace).init(); static EXECUTOR: StaticCell = StaticCell::new(); let executor = EXECUTOR.init(Executor::new()); executor.run(|spawner| { - spawner.must_spawn(power_policy_service::task(Default::default())); - spawner.must_spawn(type_c_service::task(Default::default())); + spawner.must_spawn(power_policy_service_task()); + spawner.must_spawn(type_c_service_task()); spawner.must_spawn(task(spawner)); }); } diff --git a/examples/std/src/bin/type_c/ucsi.rs b/examples/std/src/bin/type_c/ucsi.rs index de3f84a4..b34d5410 100644 --- a/examples/std/src/bin/type_c/ucsi.rs +++ b/examples/std/src/bin/type_c/ucsi.rs @@ -195,13 +195,8 @@ async fn wrapper_task(wrapper: &'static mock_controller::Wrapper<'static>) { } #[embassy_executor::task] -async fn task(spawner: Spawner) { - info!("Starting main task"); - - embedded_services::init().await; - - spawner.must_spawn(power_policy_service::task(Default::default())); - spawner.must_spawn(type_c_service::task(Config { +async fn type_c_service_task() -> ! { + type_c_service::task(Config { ucsi_capabilities: UcsiCapabilities { num_connectors: 2, bcd_usb_pd_spec: 0x0300, @@ -223,7 +218,25 @@ async fn task(spawner: Spawner) { .set_swap_to_snk(true) .set_swap_to_src(true), ), - })); + }) + .await; + unreachable!() +} + +#[embassy_executor::task] +async fn power_policy_service_task() -> ! { + power_policy_service::task::task(Default::default()).await; + unreachable!() +} + +#[embassy_executor::task] +async fn task(spawner: Spawner) { + info!("Starting main task"); + + embedded_services::init().await; + + spawner.must_spawn(power_policy_service_task()); + spawner.must_spawn(type_c_service_task()); spawner.must_spawn(opm_task(spawner)); } diff --git a/examples/std/src/bin/type_c/unconstrained.rs b/examples/std/src/bin/type_c/unconstrained.rs index 25bb8371..8117ad87 100644 --- a/examples/std/src/bin/type_c/unconstrained.rs +++ b/examples/std/src/bin/type_c/unconstrained.rs @@ -159,14 +159,26 @@ async fn task(spawner: Spawner) { Timer::after_millis(DELAY_MS).await; } +#[embassy_executor::task] +async fn type_c_service_task() -> ! { + type_c_service::task(Default::default()).await; + unreachable!() +} + +#[embassy_executor::task] +async fn power_policy_service_task() -> ! { + power_policy_service::task::task(Default::default()).await; + unreachable!() +} + fn main() { env_logger::builder().filter_level(log::LevelFilter::Trace).init(); static EXECUTOR: StaticCell = StaticCell::new(); let executor = EXECUTOR.init(Executor::new()); executor.run(|spawner| { - spawner.must_spawn(power_policy_service::task(Default::default())); - spawner.must_spawn(type_c_service::task(Default::default())); + spawner.must_spawn(power_policy_service_task()); + spawner.must_spawn(type_c_service_task()); spawner.must_spawn(task(spawner)); }); } diff --git a/hid-service/src/i2c/host.rs b/hid-service/src/i2c/host.rs index fdebcbd7..fbedabad 100644 --- a/hid-service/src/i2c/host.rs +++ b/hid-service/src/i2c/host.rs @@ -184,7 +184,7 @@ impl Host { let reg = u16::from_le_bytes(reg); trace!("Register address {:#x}", reg); - if let Some(device) = hid::get_device(self.id).await { + if let Some(device) = hid::get_device(self.id) { let request = if reg == device.regs.hid_desc_reg { hid::Request::Descriptor } else if reg == device.regs.report_desc_reg { diff --git a/hid-service/src/i2c/passthrough/interrupt.rs b/hid-service/src/i2c/passthrough/interrupt.rs index e20d40ef..d574e363 100644 --- a/hid-service/src/i2c/passthrough/interrupt.rs +++ b/hid-service/src/i2c/passthrough/interrupt.rs @@ -23,7 +23,7 @@ enum InterruptState { } impl InterruptSignal { - pub fn new(int_in: IN, int_out: OUT) -> Self { + pub const fn new(int_in: IN, int_out: OUT) -> Self { Self { state: Mutex::new(InterruptState::Idle), int_in: Mutex::new(int_in), diff --git a/hid-service/src/i2c/passthrough/mod.rs b/hid-service/src/i2c/passthrough/mod.rs index a1631e38..0a2a7009 100644 --- a/hid-service/src/i2c/passthrough/mod.rs +++ b/hid-service/src/i2c/passthrough/mod.rs @@ -5,8 +5,7 @@ pub use interrupt::*; #[macro_export] macro_rules! define_i2c_passthrough_device_task { ($bus:ty) => { - #[::embassy_executor::task] - async fn device_task(bus: $bus, id: ::embedded_services::hid::DeviceId, addr: u8) { + pub async fn device_task(bus: $bus, id: ::embedded_services::hid::DeviceId, addr: u8) { use ::embassy_sync::once_lock::OnceLock; use ::embedded_services::{define_static_buffer, error, hid, info}; use $crate::i2c::Device; @@ -32,8 +31,7 @@ macro_rules! define_i2c_passthrough_device_task { #[macro_export] macro_rules! define_i2c_passthrough_host_task { ($bus:ty, $int_in:ty, $int_out:ty) => { - #[::embassy_executor::task] - async fn host_task( + pub async fn host_task( bus: $bus, int_signal: &'static $crate::i2c::passthrough::InterruptSignal<$int_in, $int_out>, ) { @@ -84,8 +82,7 @@ macro_rules! define_i2c_passthrough_host_task { #[macro_export] macro_rules! define_i2c_passthrough_interrupt_task { ($int_in:ty, $int_out:ty) => { - #[::embassy_executor::task] - async fn interrupt_task(int_signal: &'static $crate::i2c::passthrough::InterruptSignal<$int_in, $int_out>) { + pub async fn interrupt_task(int_signal: &'static $crate::i2c::passthrough::InterruptSignal<$int_in, $int_out>) { ::embedded_services::info!("Starting interrupt task"); loop { int_signal.process().await; @@ -96,38 +93,18 @@ macro_rules! define_i2c_passthrough_interrupt_task { #[macro_export] macro_rules! define_i2c_passthrough_task { - ($name:ident, $host_bus:ty, $device_bus:ty, $int_in:ty, $int_out:ty) => { - mod $name { + ($host_bus:ty, $device_bus:ty, $int_in:ty, $int_out:ty) => { + mod task { use $crate::{ define_i2c_passthrough_device_task, define_i2c_passthrough_host_task, define_i2c_passthrough_interrupt_task, }; use super::*; - + // Spawn these 3 tasks using the executor of your choice define_i2c_passthrough_device_task!($device_bus); define_i2c_passthrough_host_task!($host_bus, $int_in, $int_out); define_i2c_passthrough_interrupt_task!($int_in, $int_out); - - pub fn spawn( - spawner: ::embassy_executor::Spawner, - host_bus: $host_bus, - device_bus: $device_bus, - device_id: ::embedded_services::hid::DeviceId, - device_addr: u8, - int_in: $int_in, - int_out: $int_out, - ) { - use ::embassy_sync::once_lock::OnceLock; - use $crate::i2c::passthrough::InterruptSignal; - - static INT_SIGNAL: OnceLock> = OnceLock::new(); - let int_signal = INT_SIGNAL.get_or_init(|| InterruptSignal::new(int_in, int_out)); - - spawner.must_spawn(device_task(device_bus, device_id, device_addr)); - spawner.must_spawn(host_task(host_bus, int_signal)); - spawner.must_spawn(interrupt_task(int_signal)); - } } }; } diff --git a/keyboard-service/Cargo.toml b/keyboard-service/Cargo.toml index 928a157d..4f105eaf 100644 --- a/keyboard-service/Cargo.toml +++ b/keyboard-service/Cargo.toml @@ -10,7 +10,6 @@ license = "MIT" [dependencies] defmt = { workspace = true, optional = true } log = { workspace = true, optional = true } -embassy-executor.workspace = true embassy-futures.workspace = true embassy-sync.workspace = true embassy-time.workspace = true @@ -28,7 +27,6 @@ defmt = [ "embedded-services/defmt", "embassy-time/defmt", "embassy-sync/defmt", - "embassy-executor/defmt", "hid-service/defmt", ] log = [ @@ -36,6 +34,5 @@ log = [ "embedded-services/log", "embassy-time/log", "embassy-sync/log", - "embassy-executor/log", "hid-service/log", ] diff --git a/keyboard-service/src/hid_kb.rs b/keyboard-service/src/hid_kb.rs index 2c4943ac..af3a5ca4 100644 --- a/keyboard-service/src/hid_kb.rs +++ b/keyboard-service/src/hid_kb.rs @@ -19,7 +19,7 @@ use static_cell::StaticCell; // with 65k bytes * queue size, so need to investigate smarter way of supporting theoretical max // efficiently. const INPUT_MAX: usize = 16; -const REPORT_DESC_MAX: usize = 256; +pub(crate) const REPORT_DESC_MAX: usize = 256; const REPORT_QUEUE_MAX: usize = 10; // The size of a HID i2c report header @@ -39,8 +39,8 @@ const REPORT_ID: u8 = 1; const REPORT_ID_SZ: usize = 1; type Report = [u8; INPUT_MAX]; -type ReportQueue = Channel; type CmdIpc = ipc::Channel, Option>>; +type ReportQueue = Channel; type ReportIpc = ipc::Channel, ()>; // A HID input report in the format HID over i2c expects @@ -90,21 +90,16 @@ impl HidI2cReport { } // Shared between tasks for communication and synchronization -struct Context { +pub(crate) struct Context { report_queue: ReportQueue, - report_ipc: ReportIpc, - cmd_ipc: CmdIpc, + pub(crate) report_ipc: ReportIpc, + pub(crate) cmd_ipc: CmdIpc, send_complete: Signal, } -static CONTEXT: OnceLock = OnceLock::new(); +pub(crate) static CONTEXT: OnceLock = OnceLock::new(); // Sets up the context, report descriptor buffer, and HID device -pub(crate) async fn init( - spawner: embassy_executor::Spawner, - hid_descriptor: hid::Descriptor, - report_descriptor: &'static [u8], - reg_file: hid::RegisterFile, -) { +pub(crate) fn init(reg_file: hid::RegisterFile) -> &'static hid::Device { // Initialize interprocess comms/synchronization context let context = Context { report_queue: ReportQueue::new(), @@ -120,102 +115,7 @@ pub(crate) async fn init( // Initialize the HID device static DEVICE: StaticCell = StaticCell::new(); let device = hid::Device::new(super::HID_KB_ID, reg_file); - let device = DEVICE.init(device); - hid::register_device(device) - .await - .expect("Device must not already be registered"); - - // Spawn device request handling task - // Other tasks are spawned by user due to need for macro to implement them because of generics - spawner.must_spawn(device_requests_task(device, hid_descriptor, report_descriptor)); -} - -// This task handles receiving HID requests from the host, -// forwarding them to the keyboard task to process, then sending a response back to host -#[embassy_executor::task] -async fn device_requests_task( - device: &'static hid::Device, - hid_descriptor: hid::Descriptor, - report_descriptor: &'static [u8], -) { - let context = CONTEXT.get().await; - - // Buffer holding hid descriptor - embedded_services::define_static_buffer!(hid_desc_buf, u8, [0u8; hid::DESCRIPTOR_LEN]); - { - let mut buf = hid_desc_buf::get_mut() - .expect("Must not already be borrowed mutably") - .borrow_mut(); - let buf: &mut [u8] = buf.borrow_mut(); - hid_descriptor - .encode_into_slice(buf) - .expect("Src and dst buffers must be same length"); - } - - // Buffer holding report descriptor - embedded_services::define_static_buffer!(report_desc_buf, u8, [0u8; REPORT_DESC_MAX]); - { - let mut buf = report_desc_buf::get_mut() - .expect("Must not already be borrowed mutably") - .borrow_mut(); - let buf: &mut [u8] = buf.borrow_mut(); - buf[..report_descriptor.len()].copy_from_slice(report_descriptor); - } - - loop { - let request = device.wait_request().await; - match request { - // For descriptors, we simply pass references to respective buffers - // These are static and never change, so don't need to do much else - hid::Request::Descriptor => { - let response = hid_desc_buf::get(); - let response = Some(hid::Response::Descriptor(response)); - device.send_response(response).await.expect("Infallible"); - } - hid::Request::ReportDescriptor => { - let response = report_desc_buf::get().slice(0..report_descriptor.len()); - let response = Some(hid::Response::ReportDescriptor(response)); - device.send_response(response).await.expect("Infallible"); - } - - // We won't receive this request unless keyboard told host we have reports available (via interrupt assert) - hid::Request::InputReport => { - // Wait for the keyboard to give us the report - let ipc = context.report_ipc.receive().await; - let report = ipc.command.clone(); - let response = Some(hid::Response::InputReport( - report.slice(0..hid_descriptor.w_max_input_length as usize), - )); - - // Then send it to the host - device.send_response(response).await.expect("Infallible"); - - // Finally tell keyboard we've sent the report so it can deassert interrupt - ipc.respond(()); - } - - // Treat this as a SET_REPORT(Output) command - // It is unclear if the behavior is meant to be different, or just different ways - // of transporting the same request. - hid::Request::OutputReport(id, buf) => { - let response = context - .cmd_ipc - .execute(hid::Command::SetReport( - hid::ReportType::Output, - id.unwrap_or(hid::ReportId(1)), - buf, - )) - .await; - device.send_response(response).await.expect("Infallible"); - } - - // Tell the keyboard to execute the requested command, waiting for it to give us a response to send to host - hid::Request::Command(cmd) => { - let response = context.cmd_ipc.execute(cmd).await; - device.send_response(response).await.expect("Infallible"); - } - } - } + DEVICE.init(device) } /// This task handles calling the keyboard `scan` in a loop, while also listening for commands diff --git a/keyboard-service/src/lib.rs b/keyboard-service/src/lib.rs index 5303dc3d..4e7e0cd8 100644 --- a/keyboard-service/src/lib.rs +++ b/keyboard-service/src/lib.rs @@ -8,6 +8,7 @@ pub mod gpio_kb; pub mod hid_kb; +pub mod task; use embedded_services::buffer::SharedRef; use embedded_services::hid; @@ -116,55 +117,3 @@ pub trait HidKeyboard { /// Gets input or feature report for the keyboard with the given report ID. fn get_report(&self, report_type: hid::ReportType, report_id: hid::ReportId) -> HidReportSlice<'_>; } - -/// Initialize the keyboard service given keyboard's HID configuration. -/// -/// The user must also ensure the `impl_hid_kb_tasks!` macro is called to implement additional generic -/// tasks and then manually spawn them. E.g.: -/// -/// ```rust,ignore -/// impl_hid_kb_tasks!(MyKeyboardType, MyI2cSlaveType, MyInterruptPinType); -/// spawner.must_spawn(keyboard_task(my_keyboard)); -/// spawner.must_spawn(reports_task(my_interrupt_pin)); -/// spawner.must_spawn(host_requests_task(my_i2c_slave)); -/// ``` -pub async fn init( - spawner: embassy_executor::Spawner, - hid_descriptor: hid::Descriptor, - report_descriptor: &'static [u8], - reg_file: hid::RegisterFile, -) { - embedded_services::hid::init(); - hid_kb::init(spawner, hid_descriptor, report_descriptor, reg_file).await -} - -// Since tasks cannot be generic, rely on this user called macro to supply the explicit type information needed -#[macro_export] -macro_rules! impl_hid_kb_tasks { - ($hid_kb_ty:ty, $i2c_slave_ty:ty, $kb_int_ty:ty) => { - #[embassy_executor::task] - pub async fn keyboard_task(hid_kb: $hid_kb_ty) { - keyboard_service::hid_kb::handle_keyboard(hid_kb).await - } - - #[embassy_executor::task] - pub async fn reports_task(kb_int: $kb_int_ty) { - keyboard_service::hid_kb::handle_reports(kb_int).await - } - - #[embassy_executor::task] - async fn host_requests_task(kb_i2c: $i2c_slave_ty) { - // Revisit: Make this buffer size configurable? - embedded_services::define_static_buffer!(hid_buf, u8, [0u8; 256]); - let buf = hid_buf::get_mut().expect("Must not already be borrowed mutably"); - - // In this macro since static items cannot be generic either - static HOST: ::static_cell::StaticCell> = - ::static_cell::StaticCell::new(); - let host = hid_service::i2c::Host::new(keyboard_service::HID_KB_ID, kb_i2c, buf); - let host = HOST.init(host); - - keyboard_service::hid_kb::handle_host_requests(host).await; - } - }; -} diff --git a/keyboard-service/src/task.rs b/keyboard-service/src/task.rs new file mode 100644 index 00000000..05e09a7b --- /dev/null +++ b/keyboard-service/src/task.rs @@ -0,0 +1,134 @@ +use core::borrow::BorrowMut; + +use embedded_services::hid; + +use crate::hid_kb::{self, CONTEXT}; + +pub async fn keyboard_task(keyboard: T) { + crate::hid_kb::handle_keyboard(keyboard).await +} + +pub async fn reports_task(keyboard_interrupt: T) { + crate::hid_kb::handle_reports(keyboard_interrupt).await +} + +// Since Rust doesn't allow defining an inner item that captures generics from an outer item, +// this must be a macro until statics are removed. +#[macro_export] +macro_rules! impl_host_request_task { + ($kb_int_ty:ty) => { + async fn host_requests_task(kb_i2c: $i2c_slave_ty) { + // Revisit: Make this buffer size configurable? + embedded_services::define_static_buffer!(hid_buf, u8, [0u8; 256]); + let buf = hid_buf::get_mut().expect("Must not already be borrowed mutably"); + + // In this macro since static items cannot be generic either + static HOST: ::static_cell::StaticCell> = + ::static_cell::StaticCell::new(); + let host = hid_service::i2c::Host::new(keyboard_service::HID_KB_ID, kb_i2c, buf); + let host = HOST.init(host); + + keyboard_service::hid_kb::handle_host_requests(host).await; + } + }; +} + +/// Initialize the keyboard service given keyboard's HID configuration. +/// +/// The user must also ensure the `impl_host_request_task!` macro is called to implement an additional +/// task and then manually spawn it. E.g.: +/// +/// ```rust,ignore +/// impl_host_request_task!(MyI2cSlaveType); +/// spawner.must_spawn(host_requests_task(my_i2c_slave)); +/// ``` +// This task handles receiving HID requests from the host, +// forwarding them to the keyboard task to process, then sending a response back to host +pub async fn init_and_recv_device_requests_task( + hid_descriptor: hid::Descriptor, + report_descriptor: &'static [u8], + reg_file: hid::RegisterFile, +) { + let device = crate::hid_kb::init(reg_file); + hid::register_device(device) + .await + .expect("Device must not already be registered"); + let context = CONTEXT.get().await; + + // Buffer holding hid descriptor + embedded_services::define_static_buffer!(hid_desc_buf, u8, [0u8; hid::DESCRIPTOR_LEN]); + { + let mut buf = hid_desc_buf::get_mut() + .expect("Must not already be borrowed mutably") + .borrow_mut(); + let buf: &mut [u8] = buf.borrow_mut(); + hid_descriptor + .encode_into_slice(buf) + .expect("Src and dst buffers must be same length"); + } + + // Buffer holding report descriptor + embedded_services::define_static_buffer!(report_desc_buf, u8, [0u8; hid_kb::REPORT_DESC_MAX]); + { + let mut buf = report_desc_buf::get_mut() + .expect("Must not already be borrowed mutably") + .borrow_mut(); + let buf: &mut [u8] = buf.borrow_mut(); + buf[..report_descriptor.len()].copy_from_slice(report_descriptor); + } + + loop { + let request = device.wait_request().await; + match request { + // For descriptors, we simply pass references to respective buffers + // These are static and never change, so don't need to do much else + hid::Request::Descriptor => { + let response = hid_desc_buf::get(); + let response = Some(hid::Response::Descriptor(response)); + device.send_response(response).await.expect("Infallible"); + } + hid::Request::ReportDescriptor => { + let response = report_desc_buf::get().slice(0..report_descriptor.len()); + let response = Some(hid::Response::ReportDescriptor(response)); + device.send_response(response).await.expect("Infallible"); + } + + // We won't receive this request unless keyboard told host we have reports available (via interrupt assert) + hid::Request::InputReport => { + // Wait for the keyboard to give us the report + let ipc = context.report_ipc.receive().await; + let report = ipc.command.clone(); + let response = Some(hid::Response::InputReport( + report.slice(0..hid_descriptor.w_max_input_length as usize), + )); + + // Then send it to the host + device.send_response(response).await.expect("Infallible"); + + // Finally tell keyboard we've sent the report so it can deassert interrupt + ipc.respond(()); + } + + // Treat this as a SET_REPORT(Output) command + // It is unclear if the behavior is meant to be different, or just different ways + // of transporting the same request. + hid::Request::OutputReport(id, buf) => { + let response = context + .cmd_ipc + .execute(hid::Command::SetReport( + hid::ReportType::Output, + id.unwrap_or(hid::ReportId(1)), + buf, + )) + .await; + device.send_response(response).await.expect("Infallible"); + } + + // Tell the keyboard to execute the requested command, waiting for it to give us a response to send to host + hid::Request::Command(cmd) => { + let response = context.cmd_ipc.execute(cmd).await; + device.send_response(response).await.expect("Infallible"); + } + } + } +} diff --git a/power-policy-service/Cargo.toml b/power-policy-service/Cargo.toml index 2a495eb6..8e661bb0 100644 --- a/power-policy-service/Cargo.toml +++ b/power-policy-service/Cargo.toml @@ -12,7 +12,6 @@ workspace = true [dependencies] defmt = { workspace = true, optional = true } -embassy-executor.workspace = true embassy-futures.workspace = true embassy-sync.workspace = true embassy-time.workspace = true @@ -27,12 +26,10 @@ defmt = [ "embedded-services/defmt", "embassy-time/defmt", "embassy-sync/defmt", - "embassy-executor/defmt", ] log = [ "dep:log", "embedded-services/log", "embassy-time/log", "embassy-sync/log", - "embassy-executor/log", ] diff --git a/power-policy-service/src/lib.rs b/power-policy-service/src/lib.rs index e939bacc..e7437f12 100644 --- a/power-policy-service/src/lib.rs +++ b/power-policy-service/src/lib.rs @@ -1,7 +1,6 @@ #![no_std] use core::ops::DerefMut; use embassy_sync::mutex::Mutex; -use embassy_sync::once_lock::OnceLock; use embedded_services::GlobalRawMutex; use embedded_services::power::policy::device::Device; use embedded_services::power::policy::{action, policy, *}; @@ -10,6 +9,7 @@ use embedded_services::{comms, error, info}; pub mod config; pub mod consumer; pub mod provider; +pub mod task; pub use config::Config; pub mod charger; @@ -165,22 +165,3 @@ impl PowerPolicy { } impl comms::MailboxDelegate for PowerPolicy {} - -#[embassy_executor::task] -pub async fn task(config: config::Config) { - info!("Starting power policy task"); - static POLICY: OnceLock = OnceLock::new(); - let policy = - POLICY.get_or_init(|| PowerPolicy::create(config).expect("Power policy singleton already initialized")); - - if comms::register_endpoint(policy, &policy.tp).await.is_err() { - error!("Failed to register power policy endpoint"); - return; - } - - loop { - if let Err(e) = policy.process().await { - error!("Error processing request: {:?}", e); - } - } -} diff --git a/power-policy-service/src/task.rs b/power-policy-service/src/task.rs new file mode 100644 index 00000000..8571149f --- /dev/null +++ b/power-policy-service/src/task.rs @@ -0,0 +1,22 @@ +use embassy_sync::once_lock::OnceLock; +use embedded_services::{comms, error, info}; + +use crate::{PowerPolicy, config}; + +pub async fn task(config: config::Config) { + info!("Starting power policy task"); + static POLICY: OnceLock = OnceLock::new(); + let policy = + POLICY.get_or_init(|| PowerPolicy::create(config).expect("Power policy singleton already initialized")); + + if comms::register_endpoint(policy, &policy.tp).await.is_err() { + error!("Failed to register power policy endpoint"); + return; + } + + loop { + if let Err(e) = policy.process().await { + error!("Error processing request: {:?}", e); + } + } +} diff --git a/thermal-service/Cargo.toml b/thermal-service/Cargo.toml index fd3694eb..f06eae3d 100644 --- a/thermal-service/Cargo.toml +++ b/thermal-service/Cargo.toml @@ -10,7 +10,6 @@ license = "MIT" [dependencies] defmt = { workspace = true, optional = true } log = { workspace = true, optional = true } -embassy-executor.workspace = true embassy-futures.workspace = true embassy-sync.workspace = true embassy-time.workspace = true @@ -30,7 +29,6 @@ defmt = [ "embedded-services/defmt", "embassy-time/defmt", "embassy-sync/defmt", - "embassy-executor/defmt", "embedded-fans-async/defmt", "embedded-sensors-hal-async/defmt", "mctp-rs/defmt", @@ -40,5 +38,4 @@ log = [ "embedded-services/log", "embassy-time/log", "embassy-sync/log", - "embassy-executor/log", ] diff --git a/thermal-service/src/fan.rs b/thermal-service/src/fan.rs index 980f3b5c..524d3d38 100644 --- a/thermal-service/src/fan.rs +++ b/thermal-service/src/fan.rs @@ -526,15 +526,3 @@ impl Fan { } } } - -/// This is a public helper macro for wrapping and spawning the various tasks since currently tasks cannot be generic -#[macro_export] -macro_rules! impl_fan_task { - ($fan_task_name:ident, $fan_type:ty, $sample_buf_len:expr) => { - #[embassy_executor::task] - pub async fn $fan_task_name(fan: &'static $crate::fan::Fan<$fan_type, $sample_buf_len>) { - let _ = - embassy_futures::join::join3(fan.handle_rx(), fan.handle_sampling(), fan.handle_auto_control()).await; - } - }; -} diff --git a/thermal-service/src/lib.rs b/thermal-service/src/lib.rs index 6e7f268e..9fabbaac 100644 --- a/thermal-service/src/lib.rs +++ b/thermal-service/src/lib.rs @@ -11,6 +11,7 @@ mod context; pub mod fan; pub mod mptf; pub mod sensor; +pub mod task; pub mod utils; /// Thermal error diff --git a/thermal-service/src/mptf.rs b/thermal-service/src/mptf.rs index 1ed8a909..ea119500 100644 --- a/thermal-service/src/mptf.rs +++ b/thermal-service/src/mptf.rs @@ -5,7 +5,7 @@ //! This interface is subject to change as the eSPI OOB service is developed use crate::{self as ts, fan, sensor, utils}; use embedded_services::ec_type::message::{StdHostPayload, StdHostRequest}; -use embedded_services::{comms, ec_type::protocols::mctp, error}; +use embedded_services::{ec_type::protocols::mctp, error}; /// MPTF Standard UUIDs which the thermal service understands pub mod uuid_standard { @@ -550,7 +550,7 @@ async fn fan_set_var(instance: u8, fan_request: fan::Request) -> Response { } } -async fn process_request(request: &mut StdHostRequest) { +pub(crate) async fn process_request(request: &mut StdHostRequest) { match request.command { embedded_services::ec_type::message::OdpCommand::Thermal(thermal_msg) => match thermal_msg { embedded_services::ec_type::protocols::mptf::ThermalCmd::GetTmp => sensor_get_tmp(request).await, @@ -564,20 +564,3 @@ async fn process_request(request: &mut StdHostRequest) { _ => error!("Thermal Service: Recvd other subsystem host message"), } } - -#[embassy_executor::task] -pub async fn handle_requests() { - loop { - let mut request = ts::wait_mctp_payload().await; - process_request(&mut request).await; - let send_result = ts::send_service_msg( - comms::EndpointID::External(comms::External::Host), - &embedded_services::ec_type::message::HostMsg::Response(request), - ) - .await; - - if send_result.is_err() { - error!("Failed to send response to MPTF request!"); - } - } -} diff --git a/thermal-service/src/sensor.rs b/thermal-service/src/sensor.rs index 57ce4815..58da7e38 100644 --- a/thermal-service/src/sensor.rs +++ b/thermal-service/src/sensor.rs @@ -476,14 +476,3 @@ impl Sensor { } } } - -/// This is a public helper macro for implementing the sensor task since tasks cannot be generic -#[macro_export] -macro_rules! impl_sensor_task { - ($sensor_task_name:ident, $sensor_type:ty, $sample_buf_len:expr) => { - #[embassy_executor::task] - pub async fn $sensor_task_name(sensor: &'static $crate::sensor::Sensor<$sensor_type, $sample_buf_len>) { - let _ = embassy_futures::join::join(sensor.handle_rx(), sensor.handle_sampling()).await; - } - }; -} diff --git a/thermal-service/src/task.rs b/thermal-service/src/task.rs new file mode 100644 index 00000000..82d21427 --- /dev/null +++ b/thermal-service/src/task.rs @@ -0,0 +1,31 @@ +use embedded_services::{comms, error}; + +use crate::{self as ts, mptf::process_request}; + +pub async fn handle_requests() { + loop { + let mut request = ts::wait_mctp_payload().await; + process_request(&mut request).await; + let send_result = ts::send_service_msg( + comms::EndpointID::External(comms::External::Host), + &embedded_services::ec_type::message::HostMsg::Response(request), + ) + .await; + + if send_result.is_err() { + error!("Failed to send response to MPTF request!"); + } + } +} + +pub async fn fan_task( + fan: &'static crate::fan::Fan, +) { + let _ = embassy_futures::join::join3(fan.handle_rx(), fan.handle_sampling(), fan.handle_auto_control()).await; +} + +pub async fn sensor_task( + sensor: &'static crate::sensor::Sensor, +) { + let _ = embassy_futures::join::join(sensor.handle_rx(), sensor.handle_sampling()).await; +} diff --git a/type-c-service/Cargo.toml b/type-c-service/Cargo.toml index 7283ac55..76f16e49 100644 --- a/type-c-service/Cargo.toml +++ b/type-c-service/Cargo.toml @@ -15,7 +15,6 @@ bitfield.workspace = true bitflags = { workspace = true } defmt = { workspace = true, optional = true } embedded-cfu-protocol.workspace = true -embassy-executor.workspace = true embassy-futures.workspace = true embassy-sync.workspace = true embassy-time.workspace = true @@ -34,10 +33,6 @@ embassy-sync = { workspace = true, features = ["std"] } critical-section = { workspace = true, features = ["std"] } embassy-time = { workspace = true, features = ["std"] } embassy-time-driver = { workspace = true } -embassy-executor = { workspace = true, features = [ - "arch-std", - "executor-thread", -] } embassy-futures.workspace = true tokio = { workspace = true, features = ["rt", "macros", "time"] } @@ -48,7 +43,6 @@ defmt = [ "embedded-services/defmt", "embassy-time/defmt", "embassy-sync/defmt", - "embassy-executor/defmt", "tps6699x/defmt", "embedded-usb-pd/defmt", ] @@ -57,6 +51,5 @@ log = [ "embedded-services/log", "embassy-time/log", "embassy-sync/log", - "embassy-executor/log", "tps6699x/log", ] diff --git a/type-c-service/src/task.rs b/type-c-service/src/task.rs index 97e97b1c..0dbdc464 100644 --- a/type-c-service/src/task.rs +++ b/type-c-service/src/task.rs @@ -42,7 +42,6 @@ pub async fn task_closure<'a, Fut: Future, F: Fn(&'a Service) -> Fu } } -#[embassy_executor::task] pub async fn task(config: Config) { task_closure(config, |service: &Service| async { if let Err(e) = service.process_next_event().await {