Refactor power policy to use direct async calls with power devices#553
Refactor power policy to use direct async calls with power devices#553RobertZ2011 wants to merge 4 commits intoOpenDevicePartnership:v0.2.0from
Conversation
1588510 to
aa3e2e0
Compare
Cargo Vet Audit Passed
|
cda7d9a to
3467d89
Compare
There was a problem hiding this comment.
Pull request overview
This PR refactors the power policy service architecture to use direct async calls instead of deferred IPC patterns. It introduces a proxy pattern for power device communication, extracts service message types into dedicated crates for better modularity, and adds comprehensive test coverage for the power policy service.
Changes:
- Refactors power policy to use direct async communication with devices via a proxy pattern
- Extracts thermal, debug, and battery service message types into separate reusable crates
- Implements MCTP relay infrastructure in embedded-services for message routing
- Adds test coverage for power policy consumer flows
Reviewed changes
Copilot reviewed 26 out of 32 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| type-c-service/src/wrapper/proxy.rs | New proxy pattern for power device communication channels |
| power-policy-service/src/*.rs | Refactored to use direct device trait calls instead of action state machine |
| thermal-service-messages/ | New crate containing thermal service request/response types |
| debug-service-messages/ | New crate containing debug service request/response types |
| battery-service-messages/ | New crate containing battery service request/response types |
| embedded-service/src/relay/ | New MCTP relay infrastructure for message serialization |
| embedded-service/src/event.rs | New event sender/receiver traits |
| embedded-service/src/power/policy/device.rs | Refactored device with InternalState and DeviceTrait |
| espi-service/src/mctp.rs | MCTP relay implementation using new infrastructure |
| power-policy-service/tests/ | New test files for consumer flows |
| examples/std/src/bin/*.rs | Updated examples for new architecture |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
4be5bff to
a838d81
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 28 out of 38 changed files in this pull request and generated 10 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
d3aa53a to
57c10a6
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 28 out of 40 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
57c10a6 to
fbe2f13
Compare
fbe2f13 to
fd95083
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 28 out of 40 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
31b3b00 to
69a1d6b
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 32 out of 45 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
bbc2ee1 to
d29f8b6
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 32 out of 45 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 32 out of 45 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 33 out of 48 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
tullom
left a comment
There was a problem hiding this comment.
Checked out locally and ran the examples. Great job with this!
|
What is the impact of this change on code size? Can we check the size of some of the examples before and after? |
* Move away from type-state type machine * Introduce first proper integration test * Create temporary bridge with type-C code
0a7d305 to
97c2fe1
Compare
With this PR, the |
asasine
left a comment
There was a problem hiding this comment.
I didn't identify anything fundamentally broken and all of my comments ultimately boiled down to nits/suggestions so approved.
| // Panic safety: The index is guaranteed to be within bounds since it comes from the select_slice result | ||
| #[allow(clippy::unwrap_used)] |
There was a problem hiding this comment.
This isn't a sufficient guarantee as the underlying list may have changed between creating the futures and their completion. There's both a panic risk here and a validity risk as index may no longer refer to the same device in that case, even if it is still within the list.
| pub async fn wait_request(&self) -> Request { | ||
| let mut futures = heapless::Vec::<_, 16>::new(); | ||
| for device in self.devices().iter_only::<device::Device<'static, D, R>>() { | ||
| // TODO: check this at compile time |
|
|
||
| /// Device struct | ||
| pub struct Device<const CHANNEL_SIZE: usize> { | ||
| pub struct Device<'a, D: Lockable, R: Receiver<RequestData>> |
There was a problem hiding this comment.
Please add documentation as to how the struct and trait with identical names are different, how they're meant to be used, and other design decisions. That the struct wraps the trait rather than implementing the trait is confusing at first glance. Consider other names too: trait DeviceTrait should probably be trait Device and struct Device is probably a different semantic thing entirely.
| #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| struct InternalState { | ||
| pub struct InternalState { |
There was a problem hiding this comment.
If it's "internal state," why is it public? That alone is smelly to me. My intuition says it should be private to some module (idk which).
| let result = if matches!( | ||
| self.state, | ||
| State::Idle | State::ConnectedConsumer(_) | State::ConnectedProvider(_) | ||
| ) { | ||
| Ok(()) | ||
| } else { | ||
| Err(Error::InvalidState( | ||
| &[StateKind::Idle, StateKind::ConnectedConsumer], | ||
| self.state.kind(), | ||
| )) | ||
| }; |
There was a problem hiding this comment.
IMO a complex matches! that's nested in other expressions is probably better served by an explicit match
| let result = if matches!( | |
| self.state, | |
| State::Idle | State::ConnectedConsumer(_) | State::ConnectedProvider(_) | |
| ) { | |
| Ok(()) | |
| } else { | |
| Err(Error::InvalidState( | |
| &[StateKind::Idle, StateKind::ConnectedConsumer], | |
| self.state.kind(), | |
| )) | |
| }; | |
| let result = match self.state { | |
| State::Idle | State::ConnectedConsumer(_) | State::ConnectedProvider(_) => Ok(()), | |
| _ => Err(Error::InvalidState( | |
| &[StateKind::Idle, StateKind::ConnectedConsumer], | |
| self.state.kind(), | |
| )), | |
| }; |
| pub state: Mutex<GlobalRawMutex, InternalState>, | ||
| /// Reference to hardware | ||
| pub device: &'a D, | ||
| /// Event receiver | ||
| pub receiver: Mutex<GlobalRawMutex, R>, |
There was a problem hiding this comment.
Can struct Device become externally mutable? Given its public methods, a RwLock<Device> seems appropriate since many of the methods would be &self, with only some methods on the inner device needing &mut self
DeviceTraittrait.impl DeviceTraitinstead of using channelstype_c_service::wrapper::proxy).