use crate::{
GroupId, MainDevice, SubDevice, SubDeviceGroup, SubDeviceRef, error::Error, fmt, pdi::PdiOffset,
};
use lock_api::RawRwLock;
#[doc(hidden)]
#[sealed::sealed]
pub trait SubDeviceGroupHandle: Sync {
fn id(&self) -> GroupId;
unsafe fn push(&self, subdevice: SubDevice) -> Result<(), Error>;
fn as_ref(&self) -> SubDeviceGroupRef<'_>;
}
#[sealed::sealed]
impl<const MAX_SUBDEVICES: usize, const MAX_PDI: usize, R: RawRwLock + Sync, S> SubDeviceGroupHandle
for SubDeviceGroup<MAX_SUBDEVICES, MAX_PDI, R, S>
where
S: Sync,
{
fn id(&self) -> GroupId {
self.id
}
unsafe fn push(&self, subdevice: SubDevice) -> Result<(), Error> {
unsafe { (*self.inner.get()).subdevices.push(subdevice) }
.map_err(|_| Error::Capacity(crate::error::Item::SubDevice))
}
fn as_ref(&self) -> SubDeviceGroupRef<'_> {
SubDeviceGroupRef {
max_pdi_len: MAX_PDI,
inner: {
let inner = unsafe { fmt::unwrap_opt!(self.inner.get().as_mut()) };
GroupInnerRef {
subdevices: &mut inner.subdevices,
pdi_start: &mut inner.pdi_start,
}
},
}
}
}
#[derive(Debug)]
struct GroupInnerRef<'a> {
subdevices: &'a mut [SubDevice],
pdi_start: &'a mut PdiOffset,
}
#[doc(alias = "SlaveGroupRef")]
pub struct SubDeviceGroupRef<'a> {
max_pdi_len: usize,
inner: GroupInnerRef<'a>,
}
impl SubDeviceGroupRef<'_> {
#[allow(clippy::wrong_self_convention)]
pub(crate) async fn into_pre_op<'sto>(
&mut self,
pdi_position: PdiOffset,
maindevice: &'sto MainDevice<'sto>,
) -> Result<PdiOffset, Error> {
let inner = &mut self.inner;
*inner.pdi_start = pdi_position;
fmt::debug!(
"Going to configure group with {} SubDevice(s), starting PDI offset {:#08x}",
inner.subdevices.len(),
inner.pdi_start.start_address
);
for subdevice in inner.subdevices.iter_mut() {
let mut subdevice_config =
SubDeviceRef::new(maindevice, subdevice.configured_address(), subdevice);
subdevice_config.configure_mailboxes().await?;
}
Ok(pdi_position.increment(self.max_pdi_len as u16))
}
}