use crate::data::error::{SyncWindowStatus, Result};
use crate::utils::ffi;
use crate::data::types::DcSyncMode;
pub struct SlaveDC {
master_index: u16,
slave_index: u16,
}
impl SlaveDC {
pub(crate) fn new(master_index: u16, slave_index: u16) -> Self {
Self { master_index, slave_index }
}
pub fn configure(&self, sync0_ns: u32, sync1_ns: u32, shift_ns: Option<i32>) -> Result<()> {
let actual_shift = match shift_ns {
Some(s) => s,
None => {
unsafe { ffi::UpdatePropagationDelays(self.master_index) };
let max_delay = unsafe { ffi::GetMaxPropagationDelay(self.master_index) };
let slave_delay = unsafe { ffi::GetSlavePropagationDelay(self.master_index, self.slave_index) };
if max_delay > 0 { max_delay - slave_delay } else { 0 }
}
};
unsafe {
ffi::SetSyncBySlaveIndex(self.master_index, self.slave_index, sync0_ns, sync1_ns, actual_shift);
}
Ok(())
}
pub fn configure_mode(&self, mode: DcSyncMode, sync0_ns: u32, sync1_ns: u32, shift_ns: Option<i32>) -> Result<()> {
match mode {
DcSyncMode::FreeRun => {
unsafe {
ffi::SetSyncBySlaveIndex(self.master_index, self.slave_index, 0, 0, 0);
}
self.configure_sm_sync_type(DcSyncMode::FreeRun);
Ok(())
}
DcSyncMode::SmSynchron => {
unsafe {
ffi::SetSyncBySlaveIndex(self.master_index, self.slave_index, 0, 0, 0);
}
self.configure_sm_sync_type(DcSyncMode::SmSynchron);
Ok(())
}
DcSyncMode::DcSynchron => {
self.configure(sync0_ns, 0, shift_ns)?;
self.configure_sm_sync_type(DcSyncMode::DcSynchron);
Ok(())
}
DcSyncMode::DcSynchron01 => {
self.configure(sync0_ns, sync1_ns, shift_ns)?;
self.configure_sm_sync_type(DcSyncMode::DcSynchron01);
Ok(())
}
}
}
fn configure_sm_sync_type(&self, mode: DcSyncMode) {
let sync_type: u8 = match mode {
DcSyncMode::FreeRun => 0,
DcSyncMode::SmSynchron => 1,
DcSyncMode::DcSynchron => 2,
DcSyncMode::DcSynchron01 => 3,
};
unsafe {
let _ = ffi::SetDcSyncMode(self.master_index, self.slave_index, sync_type);
}
}
pub fn disable(&self) {
unsafe {
ffi::SetSyncBySlaveIndex(self.master_index, self.slave_index, 0, 0, 0);
}
}
pub fn propagation_delay(&self) -> i32 {
unsafe { ffi::GetSlavePropagationDelay(self.master_index, self.slave_index) }
}
pub fn has_dc(&self) -> bool {
let ptr = unsafe { ffi::GetSlave(self.master_index, self.slave_index) };
if ptr.is_null() { return false; }
let s = unsafe { std::ptr::read_unaligned(ptr as *const ffi::EcSlaveBlittable) };
s.topo.has_dc != 0
}
pub fn dc_sync_mode_from_esi(&self) -> i32 {
unsafe { ffi::EcEsi_GetDeviceDcSyncMode(self.master_index, self.slave_index) }
}
pub fn has_esi_dc_sync(&self) -> bool {
let mode = self.dc_sync_mode_from_esi();
if mode >= 0 {
return mode >= 2;
}
if mode == -1 {
return false;
}
self.has_dc()
}
pub fn sync_window_status(&self) -> Option<SyncWindowStatus> {
let mut diff_ns: i32 = 0;
let mut max_diff_ns: i32 = 0;
let mut min_diff_ns: i32 = 0;
let mut in_sync: i32 = 0;
let mut out_of_sync_count: u32 = 0;
let ret = unsafe {
ffi::GetSlaveSyncWindowStatus(
self.master_index, self.slave_index,
&mut diff_ns, &mut max_diff_ns, &mut min_diff_ns,
&mut in_sync, &mut out_of_sync_count,
)
};
if ret != 0 {
Some(SyncWindowStatus {
diff_ns,
max_diff_ns,
min_diff_ns,
in_sync: in_sync != 0,
out_of_sync_count,
})
} else {
None
}
}
pub fn reset_sync_window_stats(&self) {
unsafe { ffi::ResetSlaveSyncWindowStats(self.master_index, self.slave_index) };
}
pub fn current_dc_sync_mode(&self) -> DcSyncMode {
let mode = unsafe { ffi::GetDcSyncMode(self.master_index, self.slave_index) };
match mode {
1 => DcSyncMode::SmSynchron,
2 => DcSyncMode::DcSynchron,
3 => DcSyncMode::DcSynchron01,
_ => DcSyncMode::FreeRun,
}
}
}
pub struct MasterDC {
master_index: u16,
}
impl MasterDC {
pub fn new(master_index: u16) -> Self {
Self { master_index }
}
pub fn enable_continuous_measurement(&self, enabled: bool, interval_sec: u32) {
unsafe {
ffi::EnableContinuousMeasurement(
self.master_index,
if enabled { 1 } else { 0 },
interval_sec,
);
}
}
pub fn enable_drift_compensation(&self, enabled: bool, threshold_ns: i32, gain: i32) {
unsafe {
ffi::EnableDriftCompensation(
self.master_index,
if enabled { 1 } else { 0 },
threshold_ns,
gain,
);
}
}
pub fn get_max_sync_difference(&self) -> i32 {
unsafe { ffi::GetMaxSyncDifference(self.master_index) }
}
pub fn is_all_slaves_in_sync(&self) -> bool {
unsafe { ffi::IsAllSlavesInSync(self.master_index) != 0 }
}
pub fn reset_all_sync_window_stats(&self) {
unsafe { ffi::ResetSlaveSyncWindowStats(self.master_index, 0); }
}
pub fn set_sync_window_threshold(&self, threshold_ns: i32) {
unsafe { ffi::SetSyncWindowThreshold(self.master_index, threshold_ns); }
}
pub fn get_sync_window_threshold(&self) -> i32 {
unsafe { ffi::GetSyncWindowThreshold(self.master_index) }
}
pub fn set_auto_shift_enabled(&self, enabled: bool) {
unsafe { ffi::SetDCAutoShiftEnabled(self.master_index, if enabled { 1 } else { 0 }); }
}
pub fn get_auto_shift_enabled(&self) -> bool {
unsafe { ffi::GetDCAutoShiftEnabled(self.master_index) != 0 }
}
pub fn master_dc_time(&self) -> u64 {
let t = unsafe { ffi::GetMasterDCTime(self.master_index) };
if t < 0 { 0 } else { t as u64 }
}
pub fn reference_clock_slave_index(&self) -> u16 {
unsafe { ffi::GetReferenceClockSlaveIndex(self.master_index) }
}
}