Skip to content

Refactor power policy to use direct async calls with power devices#553

Open
RobertZ2011 wants to merge 4 commits intoOpenDevicePartnership:v0.2.0from
RobertZ2011:power-policy-direct-async-call
Open

Refactor power policy to use direct async calls with power devices#553
RobertZ2011 wants to merge 4 commits intoOpenDevicePartnership:v0.2.0from
RobertZ2011:power-policy-direct-async-call

Conversation

@RobertZ2011
Copy link
Contributor

@RobertZ2011 RobertZ2011 commented Nov 3, 2025

  • Instead of IPC between the power policy task and power devices, direct async function calls are used through the new DeviceTrait trait.
  • Power policy now holds references to types that impl DeviceTrait instead of using channels
  • There's now a per-device channel for sending events to the power policy instead of a single shared channel
  • Remove type-stated state machines, these just ended up in a shared enum so there wasn't much benefit while resulting in duplication of common logic.
  • Introduce first power policy integration test for default consumer switching logic
  • Update examples
  • Introduce temporary bridge code until type-C code is similarly refactored (types in type_c_service::wrapper::proxy).

@RobertZ2011 RobertZ2011 self-assigned this Nov 3, 2025
@RobertZ2011 RobertZ2011 force-pushed the power-policy-direct-async-call branch from 1588510 to aa3e2e0 Compare November 4, 2025 23:15
@github-actions
Copy link

github-actions bot commented Nov 4, 2025

Cargo Vet Audit Passed

cargo vet has passed in this PR. No new unvetted dependencies were found.

@github-actions github-actions bot added the cargo vet PRs pending auditor review label Nov 4, 2025
@RobertZ2011 RobertZ2011 force-pushed the power-policy-direct-async-call branch from cda7d9a to 3467d89 Compare January 13, 2026 18:07
Copilot AI review requested due to automatic review settings January 13, 2026 18:07
@RobertZ2011 RobertZ2011 changed the base branch from main to v0.2.0 January 13, 2026 18:07
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

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.

Copilot AI review requested due to automatic review settings January 22, 2026 19:47
@RobertZ2011 RobertZ2011 force-pushed the power-policy-direct-async-call branch from 4be5bff to a838d81 Compare January 22, 2026 19:47
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

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.

Copilot AI review requested due to automatic review settings January 22, 2026 21:54
@RobertZ2011 RobertZ2011 force-pushed the power-policy-direct-async-call branch from d3aa53a to 57c10a6 Compare January 22, 2026 21:54
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

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.

@RobertZ2011 RobertZ2011 force-pushed the power-policy-direct-async-call branch from 57c10a6 to fbe2f13 Compare January 22, 2026 22:42
Copilot AI review requested due to automatic review settings January 22, 2026 22:45
@RobertZ2011 RobertZ2011 force-pushed the power-policy-direct-async-call branch from fbe2f13 to fd95083 Compare January 22, 2026 22:45
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

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.

Copilot AI review requested due to automatic review settings January 29, 2026 00:07
@RobertZ2011 RobertZ2011 force-pushed the power-policy-direct-async-call branch from 31b3b00 to 69a1d6b Compare January 29, 2026 00:07
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

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.

Copilot AI review requested due to automatic review settings January 29, 2026 19:46
@RobertZ2011 RobertZ2011 force-pushed the power-policy-direct-async-call branch from bbc2ee1 to d29f8b6 Compare January 29, 2026 19:51
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

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.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

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.

@RobertZ2011 RobertZ2011 changed the title Power policy direct async call Refactor power policy to use direct async calls Jan 29, 2026
@RobertZ2011 RobertZ2011 changed the title Refactor power policy to use direct async calls Refactor power policy to use direct async calls with power devices Jan 29, 2026
@RobertZ2011 RobertZ2011 marked this pull request as ready for review January 29, 2026 22:27
Copilot AI review requested due to automatic review settings January 29, 2026 22:27
@RobertZ2011 RobertZ2011 requested review from a team as code owners January 29, 2026 22:27
@RobertZ2011 RobertZ2011 requested a review from tullom January 29, 2026 22:27
@RobertZ2011 RobertZ2011 enabled auto-merge (squash) January 29, 2026 22:28
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

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.

Copy link
Contributor

@tullom tullom left a comment

Choose a reason for hiding this comment

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

Checked out locally and ran the examples. Great job with this!

@jerrysxie
Copy link
Contributor

What is the impact of this change on code size? Can we check the size of some of the examples before and after?

@RobertZ2011 RobertZ2011 force-pushed the power-policy-direct-async-call branch from 0a7d305 to 97c2fe1 Compare February 4, 2026 18:33
@RobertZ2011
Copy link
Contributor Author

What is the impact of this change on code size? Can we check the size of some of the examples before and after

With this PR, the rt685s-evk/type_c example shows a 19.6KiB size reduction vs ODP main (223.5KiB vs 243.1KiB).

Copy link

@asasine asasine left a comment

Choose a reason for hiding this comment

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

I didn't identify anything fundamentally broken and all of my comments ultimately boiled down to nits/suggestions so approved.

Comment on lines +248 to +249
// Panic safety: The index is guaranteed to be within bounds since it comes from the select_slice result
#[allow(clippy::unwrap_used)]
Copy link

Choose a reason for hiding this comment

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

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
Copy link

Choose a reason for hiding this comment

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

Check this what?


/// Device struct
pub struct Device<const CHANNEL_SIZE: usize> {
pub struct Device<'a, D: Lockable, R: Receiver<RequestData>>
Copy link

Choose a reason for hiding this comment

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

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 {
Copy link

Choose a reason for hiding this comment

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

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).

Comment on lines +124 to +134
let result = if matches!(
self.state,
State::Idle | State::ConnectedConsumer(_) | State::ConnectedProvider(_)
) {
Ok(())
} else {
Err(Error::InvalidState(
&[StateKind::Idle, StateKind::ConnectedConsumer],
self.state.kind(),
))
};
Copy link

Choose a reason for hiding this comment

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

IMO a complex matches! that's nested in other expressions is probably better served by an explicit match

Suggested change
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(),
)),
};

Comment on lines +276 to +280
pub state: Mutex<GlobalRawMutex, InternalState>,
/// Reference to hardware
pub device: &'a D,
/// Event receiver
pub receiver: Mutex<GlobalRawMutex, R>,
Copy link

Choose a reason for hiding this comment

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

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cargo vet PRs pending auditor review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants