Skip to content

Commit aa3e2e0

Browse files
committed
Initial power-policy integration tests
1 parent 2eb671a commit aa3e2e0

File tree

11 files changed

+497
-67
lines changed

11 files changed

+497
-67
lines changed

Cargo.lock

Lines changed: 83 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

embedded-service/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub mod buffer;
1717
pub mod cfu;
1818
pub mod comms;
1919
pub mod ec_type;
20+
pub mod event;
2021
pub mod fmt;
2122
pub mod hid;
2223
pub mod init;

embedded-service/src/power/policy/device.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
use embassy_sync::mutex::Mutex;
33

44
use super::{DeviceId, Error};
5-
use crate::power::policy::policy::EventReceiver;
5+
use crate::event::Receiver;
6+
use crate::power::policy::policy::RequestData;
67
use crate::power::policy::{ConsumerPowerCapability, ProviderPowerCapability};
78
use crate::sync::Lockable;
89
use crate::{GlobalRawMutex, intrusive_list};
@@ -117,10 +118,12 @@ pub trait DeviceTrait {
117118
fn connect_provider(&mut self, capability: ProviderPowerCapability) -> impl Future<Output = Result<(), Error>>;
118119
/// Connect this device to consume power from an external connection
119120
fn connect_consumer(&mut self, capability: ConsumerPowerCapability) -> impl Future<Output = Result<(), Error>>;
121+
/// Device is out of sync with the policy, reset and renotify power policy
122+
fn reset(&mut self) -> impl Future<Output = Result<(), Error>>;
120123
}
121124

122125
/// Device struct
123-
pub struct Device<'a, C: Lockable, R: EventReceiver>
126+
pub struct Device<'a, C: Lockable, R: Receiver<RequestData>>
124127
where
125128
C::Inner: DeviceTrait,
126129
{
@@ -133,15 +136,15 @@ where
133136
/// Reference to hardware
134137
pub device: &'a C,
135138
/// Event receiver
136-
pub receiver: &'a R,
139+
pub receiver: Mutex<GlobalRawMutex, R>,
137140
}
138141

139-
impl<'a, C: Lockable, R: EventReceiver> Device<'a, C, R>
142+
impl<'a, C: Lockable, R: Receiver<RequestData>> Device<'a, C, R>
140143
where
141144
C::Inner: DeviceTrait,
142145
{
143146
/// Create a new device
144-
pub fn new(id: DeviceId, device: &'a C, receiver: &'a R) -> Self {
147+
pub fn new(id: DeviceId, device: &'a C, receiver: R) -> Self {
145148
Self {
146149
node: intrusive_list::Node::uninit(),
147150
id,
@@ -151,7 +154,7 @@ where
151154
requested_provider_capability: None,
152155
}),
153156
device,
154-
receiver,
157+
receiver: Mutex::new(receiver),
155158
}
156159
}
157160

@@ -194,7 +197,7 @@ where
194197
}
195198
}
196199

197-
impl<C: Lockable, R: EventReceiver> intrusive_list::NodeContainer for Device<'static, C, R>
200+
impl<C: Lockable, R: Receiver<RequestData> + 'static> intrusive_list::NodeContainer for Device<'static, C, R>
198201
where
199202
C::Inner: DeviceTrait,
200203
{
@@ -204,15 +207,15 @@ where
204207
}
205208

206209
/// Trait for any container that holds a device
207-
pub trait DeviceContainer<C: Lockable, R: EventReceiver>
210+
pub trait DeviceContainer<C: Lockable, R: Receiver<RequestData>>
208211
where
209212
C::Inner: DeviceTrait,
210213
{
211214
/// Get the underlying device struct
212215
fn get_power_policy_device(&self) -> &Device<'_, C, R>;
213216
}
214217

215-
impl<C: Lockable, R: EventReceiver> DeviceContainer<C, R> for Device<'_, C, R>
218+
impl<C: Lockable, R: Receiver<RequestData>> DeviceContainer<C, R> for Device<'_, C, R>
216219
where
217220
C::Inner: DeviceTrait,
218221
{

embedded-service/src/power/policy/policy.rs

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use core::pin::pin;
44
use core::sync::atomic::{AtomicBool, Ordering};
55

66
use crate::broadcaster::immediate as broadcaster;
7+
use crate::event::{self, Receiver};
78
use crate::power::policy::device::DeviceTrait;
89
use crate::power::policy::{CommsMessage, ConsumerPowerCapability, ProviderPowerCapability};
910
use crate::sync::Lockable;
@@ -70,12 +71,7 @@ pub struct Response {
7071
}
7172

7273
/// Trait used by devices to send events to a power policy implementation
73-
pub trait EventSender {
74-
/// Try to send an event
75-
fn try_send(&mut self, event: RequestData) -> Option<()>;
76-
/// Send an event
77-
fn send(&mut self, event: RequestData) -> impl Future<Output = ()>;
78-
74+
pub trait Sender: event::Sender<RequestData> {
7975
/// Wrapper to simplify sending this event
8076
fn on_attach(&mut self) -> impl Future<Output = ()> {
8177
self.send(RequestData::Attached)
@@ -122,13 +118,7 @@ pub trait EventSender {
122118
}
123119
}
124120

125-
/// Receiver trait used by a policy implementation
126-
pub trait EventReceiver {
127-
/// Attempt to get a pending event
128-
fn try_next(&self) -> Option<RequestData>;
129-
/// Wait for the next event
130-
fn wait_next(&self) -> impl Future<Output = RequestData>;
131-
}
121+
impl<T> Sender for T where T: event::Sender<RequestData> {}
132122

133123
/// Power policy context
134124
struct Context {
@@ -158,7 +148,7 @@ pub fn init() {
158148
}
159149

160150
/// Register a device with the power policy service
161-
pub async fn register_device<C: Lockable + 'static, R: EventReceiver + 'static>(
151+
pub async fn register_device<C: Lockable + 'static, R: Receiver<RequestData> + 'static>(
162152
device: &'static impl device::DeviceContainer<C, R>,
163153
) -> Result<(), intrusive_list::Error>
164154
where
@@ -183,7 +173,7 @@ pub async fn register_charger(device: &'static impl charger::ChargerContainer) -
183173
}
184174

185175
/// Find a device by its ID
186-
async fn get_device<C: Lockable + 'static, R: EventReceiver + 'static>(
176+
async fn get_device<C: Lockable + 'static, R: Receiver<RequestData> + 'static>(
187177
id: DeviceId,
188178
) -> Option<&'static device::Device<'static, C, R>>
189179
where
@@ -249,14 +239,14 @@ pub async fn register_message_receiver(
249239
}
250240

251241
/// Singleton struct to give access to the power policy context
252-
pub struct ContextToken<D: Lockable, R: EventReceiver>
242+
pub struct ContextToken<D: Lockable, R: Receiver<RequestData>>
253243
where
254244
D::Inner: DeviceTrait,
255245
{
256246
_phantom: PhantomData<(D, R)>,
257247
}
258248

259-
impl<D: Lockable + 'static, R: EventReceiver + 'static> ContextToken<D, R>
249+
impl<D: Lockable + 'static, R: Receiver<RequestData> + 'static> ContextToken<D, R>
260250
where
261251
D::Inner: DeviceTrait,
262252
{
@@ -311,7 +301,7 @@ where
311301
let mut futures = heapless::Vec::<_, 16>::new();
312302
for device in self.devices().await.iter_only::<device::Device<'static, D, R>>() {
313303
// TODO: check this at compile time
314-
let _ = futures.push(async { device.receiver.wait_next().await });
304+
let _ = futures.push(async { device.receiver.lock().await.wait_next().await });
315305
}
316306

317307
let (event, index) = select_slice(pin!(&mut futures)).await;

power-policy-service/Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ embassy-time.workspace = true
1919
embedded-services.workspace = true
2020
log = { workspace = true, optional = true }
2121

22+
[dev-dependencies]
23+
static_cell.workspace = true
24+
critical-section = { workspace = true, features = ["std"] }
25+
embassy-time = { workspace = true, features = ["std", "generic-queue-8"] }
26+
tokio = { workspace = true, features = ["rt", "macros", "time"] }
27+
env_logger = "0.9.0"
28+
log = { workspace = true }
29+
2230
[features]
2331
default = []
2432
defmt = [

power-policy-service/src/consumer.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ fn cmp_consumer_capability(
3535
))
3636
}
3737

38-
impl<D: Lockable + 'static, R: EventReceiver + 'static> PowerPolicy<D, R>
38+
impl<D: Lockable + 'static, R: Receiver<RequestData> + 'static> PowerPolicy<D, R>
3939
where
4040
D::Inner: DeviceTrait,
4141
{
@@ -194,10 +194,13 @@ where
194194

195195
state.current_consumer_state = None;
196196
let consumer_device = self.context.get_device(current_consumer.device_id).await?;
197-
// Disconnect the current consumer if needed
198-
info!("Device{}: Disconnecting current consumer", current_consumer.device_id.0);
199-
// disconnect current consumer and set idle
200-
consumer_device.device.lock().await.disconnect().await?;
197+
if matches!(consumer_device.state().await, State::ConnectedConsumer(_)) {
198+
// Disconnect the current consumer if needed
199+
info!("Device{}: Disconnecting current consumer", current_consumer.device_id.0);
200+
// disconnect current consumer and set idle
201+
consumer_device.device.lock().await.disconnect().await?;
202+
consumer_device.state.lock().await.state = State::Idle;
203+
}
201204

202205
// If no chargers are registered, they won't receive the new power capability.
203206
// Also, if chargers return UnpoweredAck, that means the charger isn't powered.
@@ -224,6 +227,7 @@ where
224227
.await
225228
.connect_consumer(new_consumer.consumer_power_capability)
226229
.await?;
230+
device.state.lock().await.state = State::ConnectedConsumer(new_consumer.consumer_power_capability);
227231
self.post_consumer_connected(state, new_consumer).await?;
228232
Ok(())
229233
} else {

0 commit comments

Comments
 (0)