pub mod constants {
pub const ECT_MBXPROT_AOE: u16 = 0x0001;
pub const ECT_MBXPROT_EOE: u16 = 0x0002;
pub const ECT_MBXPROT_COE: u16 = 0x0004;
pub const ECT_MBXPROT_FOE: u16 = 0x0008;
pub const ECT_MBXPROT_SOE: u16 = 0x0010;
pub const ECT_MBXPROT_VOE: u16 = 0x0020;
pub const ECT_COEDET_SDO: u8 = 0x01;
pub const ECT_COEDET_SDOINFO: u8 = 0x02;
pub const ECT_COEDET_PDOASSIGN: u8 = 0x04;
pub const ECT_COEDET_PDOCONFIG: u8 = 0x08;
pub const ECT_COEDET_UPLOAD: u8 = 0x10;
pub const ECT_COEDET_SDOCA: u8 = 0x20;
}
#[derive(Clone, Debug, Default)]
#[repr(C, packed)]
pub struct PdoStats {
pub read_count: u32,
pub write_count: u32,
pub error_count: u32,
pub total_bytes_read: u32,
pub total_bytes_written: u32,
pub last_cycle_time_ns: u64,
pub min_cycle_time_ns: u64,
pub max_cycle_time_ns: u64,
pub avg_cycle_time_ns: u64,
}
#[derive(Clone, Debug)]
#[repr(C, packed)]
pub struct PdoMappingEntry {
pub index: u16,
pub sub_index: u8,
pub bit_length: u8,
pub bit_offset: u16,
pub name: [u8; 64],
pub unit: [u8; 16],
pub readable: u8,
pub writable: u8,
}
#[derive(Clone, Debug, Default)]
#[repr(C, packed)]
pub struct CommunicationStatsLocal {
pub total_cycles: u32,
pub successful_cycles: u32,
pub failed_cycles: u32,
pub timeout_cycles: u32,
pub average_cycle_time_us: f64,
pub max_cycle_time_us: f64,
pub min_cycle_time_us: f64,
}
#[derive(Clone, Debug, Default)]
pub struct SlaveInfo {
pub vendor_id: u32,
pub product_code: u32,
pub revision_number: u32,
pub serial_number: u32,
pub device_name: String,
pub vendor_name: String,
pub sync_manager_count: u16,
pub fmmu_count: u16,
pub supports_coe: bool,
pub supports_foe: bool,
pub supports_eoe: bool,
pub supports_soe: bool,
}
#[derive(Clone, Debug, Default)]
#[repr(C, packed)]
pub struct RealtimeStats {
pub current_cycle_time_us: f64,
pub jitter_us: f64,
pub lost_frames: u32,
pub corrupted_frames: u32,
pub bus_utilization: f64,
}
#[derive(Clone, Debug)]
#[repr(C, packed)]
pub struct NetworkInfo {
pub name: [u8; 128],
pub desc: [u8; 128],
pub slave_num: i16,
pub redundant_slave_num: i16,
}
#[derive(Clone, Copy, Debug, Default)]
#[repr(C, packed)]
pub struct EcSmt {
pub start_addr: u16,
pub sm_length: u16,
pub sm_flags: u32,
}
#[derive(Clone, Copy, Debug, Default)]
#[repr(C, packed)]
pub struct EcFmmut {
pub log_start: u32,
pub log_length: u16,
pub log_start_bit: u8,
pub log_end_bit: u8,
pub phys_start: u16,
pub phys_start_bit: u8,
pub fmmu_type: u8,
pub fmmu_active: u8,
pub unused1: u8,
pub unused2: u16,
}
#[derive(Clone, Copy, Debug, Default)]
#[repr(C)]
pub struct SlaveIoDesc {
pub bits: u16,
pub bytes: u32,
pub ptr: usize,
pub offset: u32,
pub startbit: u8,
}
#[derive(Clone, Copy, Debug, Default)]
#[repr(C)]
pub struct SlaveFsoe {
pub capable: u8,
pub connection: usize,
pub sm_context: usize,
pub connection_id: u16,
pub safety_address: u16,
pub safe_input_size: u16,
pub safe_output_size: u16,
pub pdo_input_offset: u32,
pub pdo_output_offset: u32,
}
#[derive(Clone, Copy, Debug, Default)]
#[repr(C)]
pub struct SlaveMailbox {
pub length: u16,
pub write_offset: u16,
pub read_length: u16,
pub read_offset: u16,
pub supported_proto: u16,
pub cnt: u8,
}
#[derive(Clone, Copy, Debug, Default)]
#[repr(C)]
pub struct SlaveEepromConfig {
pub sii_index: u16,
pub read_8byte: u8,
pub pdi: u8,
}
#[derive(Clone, Copy, Debug, Default)]
#[repr(C)]
pub struct SlaveHandler {
pub state: i32,
pub rmp_state: i32,
pub instate_ex: u16,
}
#[derive(Clone, Copy, Debug, Default)]
#[repr(C)]
pub struct SlaveIdentity {
pub vendor_id: u32,
pub product_id: u32,
pub revision: u32,
pub serial: u32,
pub itype: u16,
pub dtype: u16,
}
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct SlaveMetadata {
pub identity: SlaveIdentity,
pub group_name: [u8; 41],
pub device_name: [u8; 41],
pub sm_count: u16,
}
impl Default for SlaveMetadata {
fn default() -> Self {
Self {
identity: SlaveIdentity::default(),
group_name: [0; 41],
device_name: [0; 41],
sm_count: 0,
}
}
}
#[derive(Clone, Copy, Debug, Default)]
#[repr(C)]
pub struct SlaveCapabilities {
pub is_optional: u8,
pub supports_frame_repeat: u8,
pub mailbox_side: u8,
pub coe_details: u8,
pub foe_details: u8,
pub eoe_details: u8,
pub soe_details: u8,
}
#[derive(Clone, Copy, Debug, Default)]
#[repr(C)]
pub struct SlaveRuntime {
pub ebus_current: i16,
pub block_lrw: u8,
pub group: u8,
pub is_lost: u8,
}
#[derive(Clone, Copy, Debug, Default)]
#[repr(C)]
pub struct SlaveSmFmmu {
pub sm_type: [u8; 8],
pub sm_app_length: [u16; 8],
pub fmmu_func: [u8; 4],
pub fmmu_unused: u8,
}
#[derive(Clone, Copy, Debug, Default)]
#[repr(C)]
pub struct SlaveProtoMbx {
pub in_ptr: usize,
pub in_full: u8,
pub overrun: i32,
}
#[derive(Clone, Copy, Debug, Default)]
#[repr(C)]
pub struct SlavePdoConfig {
pub assignment_enabled: u8,
pub configuration_enabled: u8,
pub config_initialized: u8,
pub supports_complete_access: u8,
}
#[derive(Clone, Copy, Debug, Default)]
#[repr(C)]
pub struct SlaveTopology {
pub has_dc: u8,
pub phy_type: u8,
pub link_count: u8,
pub active_ports: u8,
pub consumed_ports: u8,
pub parent: u16,
pub parent_port: u8,
pub entry_port: u8,
}
#[derive(Clone, Copy, Debug, Default)]
#[repr(C)]
pub struct SlaveDc {
pub recvtime: [i32; 4],
pub propagation_delay: i32,
pub next: u16,
pub prev: u16,
pub cycle0: i32,
pub cycle1: i32,
pub shift: i32,
pub active: u16,
}
#[derive(Clone, Debug)]
#[repr(C)]
pub struct EcSlave {
pub state: u16,
pub al_status_code: u16,
pub config_addr: u16,
pub alias_addr: u16,
pub fsoe: SlaveFsoe,
pub output: SlaveIoDesc,
pub input: SlaveIoDesc,
pub sm: [EcSmt; 8],
pub fmmu: [EcFmmut; 4],
pub sm_fmmu: SlaveSmFmmu,
pub mbx: SlaveMailbox,
pub topo: SlaveTopology,
pub dc: SlaveDc,
pub eeprom_config: SlaveEepromConfig,
pub runtime: SlaveRuntime,
pub po2so_config: usize,
pub handler: SlaveHandler,
pub coe: SlaveProtoMbx,
pub soe: SlaveProtoMbx,
pub foe: SlaveProtoMbx,
pub eoe: SlaveProtoMbx,
pub voe: SlaveProtoMbx,
pub aoe: SlaveProtoMbx,
pub mbx_status: usize,
pub metadata: SlaveMetadata,
pub pdo_config: SlavePdoConfig,
pub capabilities: SlaveCapabilities,
}
#[derive(Clone, Debug)]
#[repr(C)]
pub struct EcState {
pub state: u16,
pub al_status_code: u16,
pub slave_count: i32,
pub loop_cycle: u32,
pub dc_cycle: u32,
pub dc_time: i64,
pub iomap: [u8; 65536],
pub iomap_mutex: usize,
pub iomap_buffer: [u8; 65536],
pub buffer_version: u32,
pub buffer_dirty: u8,
pub mutex_protection: u8,
pub pdo_cpu_affinity: i8,
pub dc_auto_shift_enabled: u8,
pub use_udp: u8,
pub adaptive_timeout_enabled: u8,
pub overlapping_groups: u8,
pub packed_mode: u8,
pub frame_high_priority: u8,
pub vlan_id: u16,
pub vlan_priority: u8,
pub timeout_init_to_preop: u32,
pub timeout_preop_to_safeop: u32,
pub timeout_safeop_to_op: u32,
pub wd_pd_timeout_ms: u16,
pub wd_pdi_timeout_ms: u16,
pub filter_threshold: u32,
pub frame_repeat_count: u8,
pub active_group_count: u8,
pub _group_pad: [u8; 2],
pub group_config_raw: [u8; 64],
}
#[derive(Clone, Debug)]
#[repr(C)]
pub struct InternalDiagnostics {
pub cache_cnt: u32,
pub rt_cnt: u32,
pub cycle_count: u32,
pub error_cache_cnt: u32,
pub error_cnt: u32,
pub wkc: u16,
pub expected_wkc: u16,
pub cycle_time_span: u32,
pub frame_errors: u32,
pub lost_frames: u32,
pub out_of_order_frames: u32,
pub checksum_errors: u32,
pub timeout_frames: u32,
pub rx_error_count: [u32; 512],
pub tx_error_count: [u32; 512],
pub lost_link_count: [u16; 512],
pub invalid_frame_count: [u16; 512],
pub working_counter_errors: u16,
pub consecutive_wkc_errors: u16,
pub total_wkc_mismatches: u32,
pub cycle_start_time: u64,
pub cycle_time_accumulator: f64,
pub last_snapshot_time: u64,
pub snapshot_cycle_count: u32,
pub last_cycle_time_us: f64,
pub jitter_accumulator: f64,
pub max_jitter_in_second: f64,
pub jitter_sample_count: u32,
pub avg_jitter_us: f64,
pub max_jitter_us: f64,
pub cycle_time_sample_count: u32,
pub primary_port_tx_count: u32,
pub primary_port_rx_count: u32,
pub secondary_port_tx_count: u32,
pub secondary_port_rx_count: u32,
pub primary_port_errors: u32,
pub secondary_port_errors: u32,
pub link_quality_percent: [i16; 512],
pub last_good_frame_time: [u32; 512],
pub initialized: i32,
pub enabled: i32,
pub win_frame_errors: [u32; 5],
pub win_lost_frames: [u32; 5],
pub win_out_of_order: [u32; 5],
pub win_checksum_errors: [u32; 5],
pub win_timeout_frames: [u32; 5],
pub win_wkc_errors: [u16; 5],
pub win_wkc_mismatches: [u32; 5],
pub win_primary_errors: [u32; 5],
pub win_secondary_errors: [u32; 5],
pub win_head: i32,
pub win_filled: i32,
}
#[derive(Clone, Debug)]
#[repr(C, packed)]
pub struct EcAdapterEnhanced {
pub name: [u8; 128],
pub desc: [u8; 128],
pub next: usize,
}
#[derive(Clone, Debug)]
#[repr(C, packed)]
pub struct EcStartupParam {
pub index: u16,
pub subindex: u8,
pub data: usize,
pub data_length: u32,
pub phase: u8,
pub priority: u8,
pub is_read: u8,
}
#[derive(Clone, Debug)]
#[repr(C, packed)]
pub struct EcConfigListEnhanced {
pub man: u32,
pub id: u32,
pub index: u16,
pub name: [u8; 41],
pub dtype: u8,
pub ibits: u16,
pub obits: u16,
pub sm2a: u16,
pub sm2f: u32,
pub sm3a: u16,
pub sm3f: u32,
pub fm0ac: u8,
pub fm1ac: u8,
}
#[derive(Clone, Debug)]
#[repr(C, packed)]
pub struct EcStartupListEnhanced {
pub man: u32,
pub id: u32,
pub index: u16,
pub sdo_index: u16,
pub sdo_index2: u16,
pub length: u8,
pub data: [u8; 1486],
}
#[derive(Clone, Debug)]
#[repr(C, packed)]
pub struct EcDcListEnhanced {
pub man: u32,
pub id: u32,
pub config_addr: u16,
pub sync_s: i32,
pub sync0: u32,
pub sync1: u32,
}
#[derive(Clone, Debug)]
pub struct FoEOptionsLocal {
pub enable_crc: bool,
pub strict_mode: bool,
pub auto_append_crc: bool,
pub expected_crc: u32,
}
impl Default for FoEOptionsLocal {
fn default() -> Self {
Self {
enable_crc: false,
strict_mode: true,
auto_append_crc: true,
expected_crc: 0,
}
}
}
pub struct EcGroupConfigHelper;
impl EcGroupConfigHelper {
const GROUP_CONFIG_SIZE: usize = 8;
pub fn get_group_enabled(raw: &[u8], group: u8) -> bool {
if group >= 8 { return false; }
raw[group as usize * Self::GROUP_CONFIG_SIZE] != 0
}
pub fn set_group_enabled(raw: &mut [u8], group: u8, enabled: bool) {
if group >= 8 { return; }
raw[group as usize * Self::GROUP_CONFIG_SIZE] = if enabled { 1 } else { 0 };
}
pub fn get_group_cycle_divider(raw: &[u8], group: u8) -> u8 {
if group >= 8 { return 0; }
raw[group as usize * Self::GROUP_CONFIG_SIZE + 1]
}
pub fn set_group_cycle_divider(raw: &mut [u8], group: u8, divider: u8) {
if group >= 8 { return; }
raw[group as usize * Self::GROUP_CONFIG_SIZE + 1] = divider;
}
pub fn get_group_expected_wkc(raw: &[u8], group: u8) -> u16 {
if group >= 8 { return 0; }
let off = group as usize * Self::GROUP_CONFIG_SIZE + 2;
u16::from_le_bytes([raw[off], raw[off + 1]])
}
pub fn get_group_slave_count(raw: &[u8], group: u8) -> u16 {
if group >= 8 { return 0; }
let off = group as usize * Self::GROUP_CONFIG_SIZE + 4;
u16::from_le_bytes([raw[off], raw[off + 1]])
}
pub fn get_group_frame_repeat_eligible(raw: &[u8], group: u8) -> bool {
if group >= 8 { return false; }
raw[group as usize * Self::GROUP_CONFIG_SIZE + 6] != 0
}
pub fn set_group_frame_repeat_eligible(raw: &mut [u8], group: u8, eligible: bool) {
if group >= 8 { return; }
raw[group as usize * Self::GROUP_CONFIG_SIZE + 6] = if eligible { 1 } else { 0 };
}
}