Re-implementation of rustbootd's ecat_el6695_* examples as a single binary with fixes found in review and on hardware: - DC-follow PLL hardened against period-2 hunting: slew-limited anchor (+/-50us/cycle), bistable-trap snap re-anchor, re-prime on stale deadline - drift-free absolute-grid ticker mode; probe mode for timestamp forensics - bounded-memory online stats (histograms), graceful SIGINT/SIGTERM shutdown with full report, error-streak abort - timestamp plausibility filter comparing against the previous raw sample (avoids the deadlock after a startup outlier) - XFC scope waveform options: --el2202 (with --el2202-dual), --el2262, --el1252 latch timestamp readback with per-channel edge statistics - register access unified in regs.rs: named bit constants everywhere, read-modify-write for enable/activation bytes - vendored patched ethercrab 0.7.1 (sdo_write_complete, send_raw_coe) Verified on J1900 (PREEMPT_RT 6.6.135): 600k cycles/600s exact 1 kHz, tx/rx zero errors, phase_err p50=164us std=5us; EL2202<->EL1252 loopback edge interval mean 2000.24us std=24.65us.
75 lines
2.3 KiB
Rust
75 lines
2.3 KiB
Rust
//! Configuration passed to [`MainDevice`](crate::MainDevice).
|
|
|
|
/// Configuration passed to [`MainDevice`](crate::MainDevice).
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
pub struct MainDeviceConfig {
|
|
/// The number of `FRMW` packets to send during the static phase of Distributed Clocks (DC)
|
|
/// synchronisation.
|
|
///
|
|
/// Defaults to 10000.
|
|
///
|
|
/// If this is set to zero, no static sync will be performed.
|
|
pub dc_static_sync_iterations: u32,
|
|
|
|
/// EtherCAT packet (PDU) network retry behaviour.
|
|
pub retry_behaviour: RetryBehaviour,
|
|
}
|
|
|
|
impl Default for MainDeviceConfig {
|
|
fn default() -> Self {
|
|
Self {
|
|
dc_static_sync_iterations: 10_000,
|
|
retry_behaviour: RetryBehaviour::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Network communication retry policy.
|
|
///
|
|
/// Retries will be performed at the rate defined by [`Timeouts::pdu`](field@crate::Timeouts::pdu).
|
|
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
|
|
pub enum RetryBehaviour {
|
|
/// Do not attempt to retry timed out packet sends (default).
|
|
///
|
|
/// If this option is chosen, any timeouts will raise an
|
|
/// [`Error::Timeout`](crate::error::Error::Timeout).
|
|
#[default]
|
|
None,
|
|
|
|
/// Attempt to resend a PDU up to `N` times, then raise an
|
|
/// [`Error::Timeout`](crate::error::Error::Timeout).
|
|
Count(usize),
|
|
|
|
/// Attempt to resend the PDU forever(*).
|
|
///
|
|
/// Note that this can soft-lock a program if for example the EtherCAT network cable is removed
|
|
/// as EtherCrab will attempt to resend the packet forever. It may be preferable to use
|
|
/// [`RetryBehaviour::Count`] to set an upper bound on retries.
|
|
///
|
|
/// (*) Forever in this case means a retry count of `usize::MAX`.
|
|
Forever,
|
|
}
|
|
|
|
impl RetryBehaviour {
|
|
pub(crate) const fn retry_count(&self) -> usize {
|
|
match self {
|
|
// Try at least once when used in a range like `for _ in 0..<counts>`.
|
|
RetryBehaviour::None => 0,
|
|
RetryBehaviour::Count(n) => *n,
|
|
RetryBehaviour::Forever => usize::MAX,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn retry_count_sanity_check() {
|
|
assert_eq!(RetryBehaviour::None.retry_count(), 0);
|
|
assert_eq!(RetryBehaviour::Count(10).retry_count(), 10);
|
|
assert_eq!(RetryBehaviour::Forever.retry_count(), usize::MAX);
|
|
}
|
|
}
|