Skip to content

Commit 65e003d

Browse files
committed
type-c-service/ucsi: Add support for async events
* Port events signal UCSI connector change events. The type-C service implementation broadcasts these events to allow for OPM notification. The service also tracks pending events, reports them in the returned CCI, and clears them following an ACK_CC_CI. * Move type-C service away from comms messages * Update examples
1 parent 35cba7d commit 65e003d

File tree

12 files changed

+257
-179
lines changed

12 files changed

+257
-179
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

embedded-service/src/type_c/comms.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,23 @@ pub struct DebugAccessoryMessage {
1111
/// Connected
1212
pub connected: bool,
1313
}
14+
15+
/// UCSI connector change message
16+
#[derive(Copy, Clone, Debug)]
17+
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
18+
pub struct UcsiCiMessage {
19+
/// Port
20+
pub port: GlobalPortId,
21+
/// Notify OPM
22+
pub notify_opm: bool,
23+
}
24+
25+
/// Top-level comms message
26+
#[derive(Copy, Clone, Debug)]
27+
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
28+
pub enum CommsMessage {
29+
/// Debug accessory message
30+
DebugAccessory(DebugAccessoryMessage),
31+
/// UCSI CCI message
32+
UcsiCci(UcsiCiMessage),
33+
}

embedded-service/src/type_c/controller.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ use super::{ATTN_VDM_LEN, ControllerId, OTHER_VDM_LEN, external};
1717
use crate::ipc::deferred;
1818
use crate::power::policy;
1919
use crate::type_c::Cached;
20+
use crate::type_c::comms::CommsMessage;
2021
use crate::type_c::event::{PortEvent, PortPending};
21-
use crate::{GlobalRawMutex, IntrusiveNode, error, intrusive_list, trace};
22+
use crate::{GlobalRawMutex, IntrusiveNode, broadcaster::immediate as broadcaster, error, intrusive_list, trace};
2223

2324
/// maximum number of data objects in a VDM
2425
pub const MAX_NUM_DATA_OBJECTS: usize = 7; // 7 VDOs of 4 bytes each
@@ -674,6 +675,8 @@ struct Context {
674675
port_events: Signal<GlobalRawMutex, PortPending>,
675676
/// Channel for receiving commands to the type-C service
676677
external_command: deferred::Channel<GlobalRawMutex, external::Command, external::Response<'static>>,
678+
/// Event broadcaster
679+
broadcaster: broadcaster::Immediate<CommsMessage>,
677680
}
678681

679682
impl Context {
@@ -682,6 +685,7 @@ impl Context {
682685
controllers: intrusive_list::IntrusiveList::new(),
683686
port_events: Signal::new(),
684687
external_command: deferred::Channel::new(),
688+
broadcaster: broadcaster::Immediate::default(),
685689
}
686690
}
687691

@@ -741,6 +745,13 @@ pub(super) async fn get_num_ports() -> usize {
741745
.fold(0, |acc, controller| acc + controller.num_ports())
742746
}
743747

748+
/// Register a message receiver for type-C messages
749+
pub async fn register_message_receiver(
750+
receiver: &'static broadcaster::Receiver<'_, CommsMessage>,
751+
) -> intrusive_list::Result<()> {
752+
CONTEXT.get().await.broadcaster.register_receiver(receiver)
753+
}
754+
744755
/// Default command timeout
745756
/// set to high value since this is intended to prevent an unresponsive device from blocking the service implementation
746757
const DEFAULT_TIMEOUT: Duration = Duration::from_millis(5000);
@@ -1214,6 +1225,11 @@ impl ContextToken {
12141225
_ => Err(PdError::InvalidResponse),
12151226
}
12161227
}
1228+
1229+
/// Broadcast a type-C message to all subscribers
1230+
pub async fn broadcast_message(&self, message: CommsMessage) {
1231+
CONTEXT.get().await.broadcaster.broadcast(message).await;
1232+
}
12171233
}
12181234

12191235
/// Execute an external port command

embedded-service/src/type_c/event.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,12 @@ impl From<PortPending> for u32 {
444444
}
445445
}
446446

447+
impl Default for PortPending {
448+
fn default() -> Self {
449+
Self::none()
450+
}
451+
}
452+
447453
impl FromIterator<usize> for PortPending {
448454
fn from_iter<T: IntoIterator<Item = usize>>(iter: T) -> Self {
449455
let mut flags = PortPending::none();

examples/rt633/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/rt685s-evk/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/rt685s-evk/Cargo.toml

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,9 @@ embassy-imxrt = { git = "https://github.com/OpenDevicePartnership/embassy-imxrt"
2929
"mimxrt685s",
3030
] }
3131

32-
embassy-embedded-hal = { version = "0.5.0", features = [
33-
"defmt",
34-
] }
32+
embassy-embedded-hal = { version = "0.5.0", features = ["defmt"] }
3533

36-
embassy-sync = { version = "0.7.2", features = [
37-
"defmt",
38-
] }
34+
embassy-sync = { version = "0.7.2", features = ["defmt"] }
3935
embassy-executor = { version = "0.9.1", features = [
4036
"arch-cortex-m",
4137
"executor-thread",

examples/rt685s-evk/src/bin/type_c.rs

Lines changed: 1 addition & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ use embassy_imxrt::{bind_interrupts, peripherals};
1111
use embassy_sync::mutex::Mutex;
1212
use embassy_time::{self as _, Delay};
1313
use embedded_cfu_protocol::protocol_definitions::{FwUpdateOffer, FwUpdateOfferResponse, FwVersion, HostToken};
14+
use embedded_services::GlobalRawMutex;
1415
use embedded_services::power::policy::DeviceId as PowerId;
1516
use embedded_services::type_c::{self, Cached, ControllerId};
16-
use embedded_services::{GlobalRawMutex, comms};
1717
use embedded_services::{error, info};
1818
use embedded_usb_pd::GlobalPortId;
1919
use static_cell::StaticCell;
@@ -48,78 +48,6 @@ type Wrapper<'a> = Tps6699xWrapper<'a, GlobalRawMutex, BusDevice<'a>, Validator>
4848
type Controller<'a> = tps6699x::controller::Controller<GlobalRawMutex, BusDevice<'a>>;
4949
type Interrupt<'a> = tps6699x::Interrupt<'a, GlobalRawMutex, BusDevice<'a>>;
5050

51-
/// Battery mock that receives messages from power policy
52-
mod battery {
53-
use defmt::{info, trace};
54-
use embedded_services::comms;
55-
use embedded_services::power::policy;
56-
57-
pub struct Device {
58-
pub tp: comms::Endpoint,
59-
}
60-
61-
impl Device {
62-
pub fn new() -> Self {
63-
Self {
64-
tp: comms::Endpoint::uninit(comms::EndpointID::Internal(comms::Internal::Battery)),
65-
}
66-
}
67-
}
68-
69-
impl comms::MailboxDelegate for Device {
70-
fn receive(&self, message: &comms::Message) -> Result<(), comms::MailboxDelegateError> {
71-
trace!("Got message");
72-
73-
let message = message
74-
.data
75-
.get::<policy::CommsMessage>()
76-
.ok_or(comms::MailboxDelegateError::MessageNotFound)?;
77-
78-
match message.data {
79-
policy::CommsData::ConsumerDisconnected(id) => {
80-
info!("Consumer disconnected: {}", id.0);
81-
Ok(())
82-
}
83-
policy::CommsData::ConsumerConnected(id, capability) => {
84-
info!("Consumer connected: {} {:?}", id.0, capability);
85-
Ok(())
86-
}
87-
_ => Ok(()),
88-
}
89-
}
90-
}
91-
}
92-
93-
/// Debug accesory listener mock
94-
mod debug {
95-
use defmt::{info, trace};
96-
use embedded_services::comms;
97-
use embedded_services::type_c;
98-
99-
pub struct Device {
100-
pub tp: comms::Endpoint,
101-
}
102-
103-
impl Device {
104-
pub fn new() -> Self {
105-
Self {
106-
tp: comms::Endpoint::uninit(comms::EndpointID::Internal(comms::Internal::Usbc)),
107-
}
108-
}
109-
}
110-
111-
impl comms::MailboxDelegate for Device {
112-
fn receive(&self, message: &comms::Message) -> Result<(), comms::MailboxDelegateError> {
113-
trace!("Got message");
114-
if let Some(message) = message.data.get::<type_c::comms::DebugAccessoryMessage>() {
115-
info!("Debug accessory message: {:?}", message);
116-
}
117-
118-
Ok(())
119-
}
120-
}
121-
}
122-
12351
#[embassy_executor::task]
12452
async fn pd_controller_task(controller: &'static Wrapper<'static>) {
12553
loop {
@@ -200,17 +128,6 @@ async fn main(spawner: Spawner) {
200128
pd_controller.register().await.unwrap();
201129
spawner.must_spawn(pd_controller_task(pd_controller));
202130

203-
static BATTERY: StaticCell<battery::Device> = StaticCell::new();
204-
let battery = BATTERY.init(battery::Device::new());
205-
206-
comms::register_endpoint(battery, &battery.tp).await.unwrap();
207-
208-
static DEBUG_ACCESSORY: StaticCell<debug::Device> = StaticCell::new();
209-
let debug_accessory = DEBUG_ACCESSORY.init(debug::Device::new());
210-
comms::register_endpoint(debug_accessory, &debug_accessory.tp)
211-
.await
212-
.unwrap();
213-
214131
// Sync our internal state with the hardware
215132
type_c::external::sync_controller_state(CONTROLLER0_ID).await.unwrap();
216133

examples/std/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)