Skip to content
Merged
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ A pure Rust EtherCAT MainDevice supporting std and no_std environments.

- **(breaking)** [#298](https://github.com/ethercrab-rs/ethercrab/pull/298) Change MSRV from 1.81 to
1.85, migrate to edition 2024.
- **(breaking)** [#331](https://github.com/ethercrab-rs/ethercrab/pull/331) (@theol0403) Use
`lock_api` traits to allow for different locking behaviour.
- [#301](https://github.com/ethercrab-rs/ethercrab/pull/301) No longer warn when mailbox counter is
not what was sent by the MainDevice.
- **(breaking)** [#320](https://github.com/ethercrab-rs/ethercrab/pull/320) (@fpdotmonkey) Add
Expand Down
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ sealed = "0.6.0"
serde = { version = "1.0.190", features = ["derive"], optional = true }
smlang = "0.8.0"
ethercrab-wire = { version = "0.2.0", path = "./ethercrab-wire" }
spin = { version = "0.10.0", default-features = false, features = ["rwlock"] }
spin = { version = "0.10.0", default-features = false, features = ["lock_api", "rwlock"] }
crc = { version = "3.2.1", default-features = false }
lock_api = "0.4.13"

[target.'cfg(target_os = "windows")'.dependencies]
pnet_datalink = { version = "0.35.0", features = ["std"], optional = true }
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,9 @@ const MAINDEVICE_ADDR: EthernetAddress = EthernetAddress([0x10, 0x10, 0x10, 0x10
const BASE_SUBDEVICE_ADDRESS: u16 = 0x1000;

#[cfg(feature = "std")]
type SpinStrategy = spin::Yield;
type DefaultLock = spin::rwlock::RwLock<(), spin::Yield>;
#[cfg(not(feature = "std"))]
type SpinStrategy = spin::Spin;
type DefaultLock = spin::rwlock::RwLock<(), spin::Spin>;

#[allow(unused)]
fn test_logger() {
Expand Down
5 changes: 4 additions & 1 deletion src/maindevice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,10 @@ impl<'sto> MainDevice<'sto> {
pub async fn init_single_group<const MAX_SUBDEVICES: usize, const MAX_PDI: usize>(
&self,
now: impl Fn() -> u64 + Copy,
) -> Result<SubDeviceGroup<MAX_SUBDEVICES, MAX_PDI, subdevice_group::PreOp>, Error> {
) -> Result<
SubDeviceGroup<MAX_SUBDEVICES, MAX_PDI, crate::DefaultLock, subdevice_group::PreOp>,
Error,
> {
self.init::<MAX_SUBDEVICES, _>(now, Default::default(), |group, _subdevice| Ok(group))
.await
}
Expand Down
56 changes: 29 additions & 27 deletions src/subdevice/pdi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ use core::{
marker::PhantomData,
ops::{Deref, DerefMut, Range},
};
use lock_api::{RawRwLock, RwLock, RwLockReadGuard, RwLockWriteGuard};

pub struct PdiReadGuard<'a, const N: usize> {
lock: spin::RwLockReadGuard<'a, MySyncUnsafeCell<[u8; N]>>,
pub struct PdiReadGuard<'a, const N: usize, R: RawRwLock> {
lock: RwLockReadGuard<'a, R, MySyncUnsafeCell<[u8; N]>>,
range: Range<usize>,
_lt: PhantomData<&'a ()>,
}

impl<const N: usize> Deref for PdiReadGuard<'_, N> {
impl<const N: usize, R: RawRwLock> Deref for PdiReadGuard<'_, N, R> {
type Target = [u8];

fn deref(&self) -> &Self::Target {
Expand All @@ -21,13 +22,13 @@ impl<const N: usize> Deref for PdiReadGuard<'_, N> {
}
}

pub struct PdiIoRawReadGuard<'a, const N: usize> {
lock: spin::RwLockReadGuard<'a, MySyncUnsafeCell<[u8; N]>>,
pub struct PdiIoRawReadGuard<'a, const N: usize, R: RawRwLock> {
lock: RwLockReadGuard<'a, R, MySyncUnsafeCell<[u8; N]>>,
ranges: IoRanges,
_lt: PhantomData<&'a ()>,
}

impl<const N: usize> PdiIoRawReadGuard<'_, N> {
impl<const N: usize, R: RawRwLock> PdiIoRawReadGuard<'_, N, R> {
pub fn inputs(&self) -> &[u8] {
let all = unsafe { &*self.lock.get() }.as_slice();

Expand All @@ -41,13 +42,13 @@ impl<const N: usize> PdiIoRawReadGuard<'_, N> {
}
}

pub struct PdiIoRawWriteGuard<'a, const N: usize> {
lock: spin::rwlock::RwLockWriteGuard<'a, MySyncUnsafeCell<[u8; N]>, crate::SpinStrategy>,
pub struct PdiIoRawWriteGuard<'a, const N: usize, R: RawRwLock> {
lock: RwLockWriteGuard<'a, R, MySyncUnsafeCell<[u8; N]>>,
ranges: IoRanges,
_lt: PhantomData<&'a ()>,
}

impl<const N: usize> PdiIoRawWriteGuard<'_, N> {
impl<const N: usize, R: RawRwLock> PdiIoRawWriteGuard<'_, N, R> {
pub fn inputs(&self) -> &[u8] {
let all = unsafe { &*self.lock.get() }.as_slice();

Expand All @@ -61,13 +62,13 @@ impl<const N: usize> PdiIoRawWriteGuard<'_, N> {
}
}

pub struct PdiWriteGuard<'a, const N: usize> {
lock: spin::rwlock::RwLockWriteGuard<'a, MySyncUnsafeCell<[u8; N]>, crate::SpinStrategy>,
pub struct PdiWriteGuard<'a, const N: usize, R: RawRwLock> {
lock: RwLockWriteGuard<'a, R, MySyncUnsafeCell<[u8; N]>>,
range: Range<usize>,
_lt: PhantomData<&'a ()>,
}

impl<const N: usize> Deref for PdiWriteGuard<'_, N> {
impl<const N: usize, R: RawRwLock> Deref for PdiWriteGuard<'_, N, R> {
type Target = [u8];

fn deref(&self) -> &Self::Target {
Expand All @@ -77,7 +78,7 @@ impl<const N: usize> Deref for PdiWriteGuard<'_, N> {
}
}

impl<const N: usize> DerefMut for PdiWriteGuard<'_, N> {
impl<const N: usize, R: RawRwLock> DerefMut for PdiWriteGuard<'_, N, R> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.lock.get_mut()[self.range.clone()]
}
Expand All @@ -87,33 +88,33 @@ impl<const N: usize> DerefMut for PdiWriteGuard<'_, N> {
///
/// Used in conjunction with [`SubDeviceRef`].
#[doc(alias = "SlavePdi")]
pub struct SubDevicePdi<'group, const MAX_PDI: usize> {
pub struct SubDevicePdi<'group, const MAX_PDI: usize, R: RawRwLock> {
subdevice: &'group SubDevice,
pdi: &'group spin::rwlock::RwLock<MySyncUnsafeCell<[u8; MAX_PDI]>, crate::SpinStrategy>,
pdi: &'group RwLock<R, MySyncUnsafeCell<[u8; MAX_PDI]>>,
}

unsafe impl<const MAX_PDI: usize> Send for SubDevicePdi<'_, MAX_PDI> {}
unsafe impl<const MAX_PDI: usize> Sync for SubDevicePdi<'_, MAX_PDI> {}
unsafe impl<const MAX_PDI: usize, R: RawRwLock> Send for SubDevicePdi<'_, MAX_PDI, R> {}
unsafe impl<const MAX_PDI: usize, R: RawRwLock> Sync for SubDevicePdi<'_, MAX_PDI, R> {}

impl<const MAX_PDI: usize> Deref for SubDevicePdi<'_, MAX_PDI> {
impl<const MAX_PDI: usize, R: RawRwLock> Deref for SubDevicePdi<'_, MAX_PDI, R> {
type Target = SubDevice;

fn deref(&self) -> &Self::Target {
self.subdevice
}
}

impl<'group, const MAX_PDI: usize> SubDevicePdi<'group, MAX_PDI> {
impl<'group, const MAX_PDI: usize, R: RawRwLock> SubDevicePdi<'group, MAX_PDI, R> {
pub(crate) fn new(
subdevice: &'group SubDevice,
pdi: &'group spin::rwlock::RwLock<MySyncUnsafeCell<[u8; MAX_PDI]>, crate::SpinStrategy>,
pdi: &'group RwLock<R, MySyncUnsafeCell<[u8; MAX_PDI]>>,
) -> Self {
Self { subdevice, pdi }
}
}

/// Methods used when a SubDevice is part of a group and part of the PDI has been mapped to it.
impl<const MAX_PDI: usize> SubDeviceRef<'_, SubDevicePdi<'_, MAX_PDI>> {
impl<const MAX_PDI: usize, R: RawRwLock> SubDeviceRef<'_, SubDevicePdi<'_, MAX_PDI, R>> {
/// Get a reference to the raw inputs and outputs for this SubDevice in the Process Data Image
/// (PDI). The inputs are read-only, while the outputs can be mutated.
///
Expand All @@ -136,7 +137,7 @@ impl<const MAX_PDI: usize> SubDeviceRef<'_, SubDevicePdi<'_, MAX_PDI>> {
/// io.outputs()[0] = 0xaa;
/// # }
/// ```
pub fn io_raw_mut(&self) -> PdiIoRawWriteGuard<'_, MAX_PDI> {
pub fn io_raw_mut(&self) -> PdiIoRawWriteGuard<'_, MAX_PDI, R> {
PdiIoRawWriteGuard {
lock: self.state.pdi.write(),
ranges: self.state.config.io.clone(),
Expand Down Expand Up @@ -175,7 +176,7 @@ impl<const MAX_PDI: usize> SubDeviceRef<'_, SubDevicePdi<'_, MAX_PDI>> {
/// dbg!(io.outputs()[0]);
/// # }
/// ```
pub fn io_raw(&self) -> PdiIoRawReadGuard<'_, MAX_PDI> {
pub fn io_raw(&self) -> PdiIoRawReadGuard<'_, MAX_PDI, R> {
PdiIoRawReadGuard {
lock: self.state.pdi.read(),
ranges: self.state.config.io.clone(),
Expand All @@ -184,7 +185,7 @@ impl<const MAX_PDI: usize> SubDeviceRef<'_, SubDevicePdi<'_, MAX_PDI>> {
}

/// Get a reference to the raw input data for this SubDevice in the Process Data Image (PDI).
pub fn inputs_raw(&self) -> PdiReadGuard<'_, MAX_PDI> {
pub fn inputs_raw(&self) -> PdiReadGuard<'_, MAX_PDI, R> {
PdiReadGuard {
lock: self.state.pdi.read(),
range: self.state.config.io.input.bytes.clone(),
Expand All @@ -193,7 +194,7 @@ impl<const MAX_PDI: usize> SubDeviceRef<'_, SubDevicePdi<'_, MAX_PDI>> {
}

/// Get a reference to the raw output data for this SubDevice in the Process Data Image (PDI).
pub fn outputs_raw(&self) -> PdiReadGuard<'_, MAX_PDI> {
pub fn outputs_raw(&self) -> PdiReadGuard<'_, MAX_PDI, R> {
PdiReadGuard {
lock: self.state.pdi.read(),
range: self.state.config.io.output.bytes.clone(),
Expand All @@ -203,7 +204,7 @@ impl<const MAX_PDI: usize> SubDeviceRef<'_, SubDevicePdi<'_, MAX_PDI>> {

/// Get a mutable reference to the raw output data for this SubDevice in the Process Data Image
/// (PDI).
pub fn outputs_raw_mut(&self) -> PdiWriteGuard<'_, MAX_PDI> {
pub fn outputs_raw_mut(&self) -> PdiWriteGuard<'_, MAX_PDI, R> {
PdiWriteGuard {
lock: self.state.pdi.write(),
range: self.state.config.io.output.bytes.clone(),
Expand Down Expand Up @@ -238,7 +239,8 @@ mod tests {

const LEN: usize = 64;

let pdi_storage = spin::rwlock::RwLock::new(MySyncUnsafeCell::new([0xabu8; LEN]));
let pdi_storage =
RwLock::<crate::DefaultLock, _>::new(MySyncUnsafeCell::new([0xabu8; LEN]));

let pdi = SubDevicePdi::new(&sd, &pdi_storage);

Expand Down
6 changes: 3 additions & 3 deletions src/subdevice_group/group_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ mod tests {

#[test]
fn group_unique_id_defaults() {
let g1 = SubDeviceGroup::<16, 16, PreOp>::default();
let g2 = SubDeviceGroup::<16, 16, PreOp>::default();
let g3 = SubDeviceGroup::<16, 16, PreOp>::default();
let g1 = SubDeviceGroup::<16, 16, crate::DefaultLock, PreOp>::default();
let g2 = SubDeviceGroup::<16, 16, crate::DefaultLock, PreOp>::default();
let g3 = SubDeviceGroup::<16, 16, crate::DefaultLock, PreOp>::default();

assert_ne!(g1.id, g2.id);
assert_ne!(g2.id, g3.id);
Expand Down
5 changes: 3 additions & 2 deletions src/subdevice_group/handle.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::{
GroupId, MainDevice, SubDevice, SubDeviceGroup, SubDeviceRef, error::Error, fmt, pdi::PdiOffset,
};
use lock_api::RawRwLock;

/// A trait implemented only by [`SubDeviceGroup`] so multiple groups with different const params
/// can be stored in a hashmap, `Vec`, etc.
Expand All @@ -18,8 +19,8 @@ pub trait SubDeviceGroupHandle: Sync {
}

#[sealed::sealed]
impl<const MAX_SUBDEVICES: usize, const MAX_PDI: usize, S> SubDeviceGroupHandle
for SubDeviceGroup<MAX_SUBDEVICES, MAX_PDI, S>
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,
{
Expand Down
Loading