Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better safe-op/op transitions #240

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions examples/dc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,22 +356,30 @@ fn main() -> Result<(), Error> {
// Send PDI and check group state until all SubDevices enter OP state. At this point, we can
// exit this loop and enter the main process data loop that does not have the state check
// overhead present here.
loop {
let mut group = loop {
let now = Instant::now();

let (
_wkc,
CycleInfo {
next_cycle_wait, ..
},
) = group.tx_rx_dc(&maindevice).await.expect("TX/RX");
transition_token,
) = group
.tx_rx_dc_check_state(&maindevice)
.await
.expect("TX/RX");

if group.all_op(&maindevice).await? {
break;
if let Some(token) = transition_token {
break group.into_state(token);
}

// if group.all_op(&maindevice).await? {
// break;
// }

smol::Timer::at(now + next_cycle_wait).await;
}
};

log::info!(
"All SubDevices entered OP in {} us",
Expand Down
62 changes: 43 additions & 19 deletions src/subdevice_group/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,19 +73,30 @@ pub struct HasDc {
reference: u16,
}

/// A state where a [`SubDeviceGroup`] has requested a state change and is currently transitioning.
pub struct Transitioning<FROM, TO>(FROM, TO);

/// A sealed token returned by EtherCrab to allow end user code to transition a group after
/// EtherCrab has validated it can do so.
///
/// This token may not be created by user code.
pub struct TransitionToken<T>(T);

/// Marker trait for `SubDeviceGroup` typestates where all SubDevices have a PDI.
#[doc(hidden)]
pub trait HasPdi {}

impl HasPdi for PreOpPdi {}
impl HasPdi for SafeOp {}
impl HasPdi for Op {}
impl<FROM, TO> HasPdi for Transitioning<FROM, TO> where FROM: HasPdi {}

#[doc(hidden)]
pub trait IsPreOp {}

impl IsPreOp for PreOp {}
impl IsPreOp for PreOpPdi {}
impl<FROM, TO> IsPreOp for Transitioning<FROM, TO> where FROM: IsPreOp {}

#[derive(Default)]
struct GroupInner<const MAX_SUBDEVICES: usize> {
Expand Down Expand Up @@ -488,7 +499,7 @@ impl<const MAX_SUBDEVICES: usize, const MAX_PDI: usize, DC>
pub async fn request_into_op(
self,
maindevice: &MainDevice<'_>,
) -> Result<SubDeviceGroup<MAX_SUBDEVICES, MAX_PDI, Op, DC>, Error> {
) -> Result<SubDeviceGroup<MAX_SUBDEVICES, MAX_PDI, Transitioning<SafeOp, Op>, DC>, Error> {
let self_ = self.into_safe_op(maindevice).await?;

self_.request_into_op(maindevice).await
Expand Down Expand Up @@ -533,18 +544,9 @@ impl<const MAX_SUBDEVICES: usize, const MAX_PDI: usize, DC>
pub async fn request_into_op(
mut self,
maindevice: &MainDevice<'_>,
) -> Result<SubDeviceGroup<MAX_SUBDEVICES, MAX_PDI, Op, DC>, Error> {
for subdevice in self
.inner
.get_mut()
.subdevices
.iter_mut()
.map(|subdevice| subdevice.get_mut())
{
SubDeviceRef::new(maindevice, subdevice.configured_address(), subdevice)
.request_subdevice_state_nowait(SubDeviceState::Op)
.await?;
}
) -> Result<SubDeviceGroup<MAX_SUBDEVICES, MAX_PDI, Transitioning<SafeOp, Op>, DC>, Error> {
self.set_subdevice_states(maindevice, SubDeviceState::Op)
.await?;

Ok(SubDeviceGroup {
id: self.id,
Expand Down Expand Up @@ -738,14 +740,11 @@ impl<const MAX_SUBDEVICES: usize, const MAX_PDI: usize, S, DC>
.await
}

/// Transition to a new state.
async fn transition_to<TO>(
mut self,
async fn set_subdevice_states(
&mut self,
maindevice: &MainDevice<'_>,
desired_state: SubDeviceState,
) -> Result<SubDeviceGroup<MAX_SUBDEVICES, MAX_PDI, TO, DC>, Error> {
// We're done configuring FMMUs, etc, now we can request all SubDevices in this group go into
// SAFE-OP
) -> Result<(), Error> {
for subdevice in self
.inner
.get_mut()
Expand All @@ -758,6 +757,19 @@ impl<const MAX_SUBDEVICES: usize, const MAX_PDI: usize, S, DC>
.await?;
}

Ok(())
}

/// Transition to a new state.
async fn transition_to<TO>(
mut self,
maindevice: &MainDevice<'_>,
desired_state: SubDeviceState,
) -> Result<SubDeviceGroup<MAX_SUBDEVICES, MAX_PDI, TO, DC>, Error> {
// We're done configuring FMMUs, etc, now we can request all SubDevices in this group go into
// SAFE-OP
self.set_subdevice_states(maindevice, desired_state).await?;

fmt::debug!("Waiting for group state {}", desired_state);

self.wait_for_state(maindevice, desired_state).await?;
Expand Down Expand Up @@ -1197,3 +1209,15 @@ where
))
}
}

impl<const MAX_SUBDEVICES: usize, const MAX_PDI: usize>
SubDeviceGroup<MAX_SUBDEVICES, MAX_PDI, Transitioning<SafeOp, Op>, HasDc>
{
/// Transmit PDI, DC sync frame and check if all SubDevices have reached the desired state.
pub async fn tx_rx_dc_check_state(
&self,
maindevice: &MainDevice<'_>,
) -> Result<(u16, CycleInfo, TransitionToken<Op>), Error> {
todo!()
}
}