1
2pub mod constants {
3
4 pub const ECT_MBXPROT_AOE: u16 = 0x0001;
5
6 pub const ECT_MBXPROT_EOE: u16 = 0x0002;
7
8 pub const ECT_MBXPROT_COE: u16 = 0x0004;
9
10 pub const ECT_MBXPROT_FOE: u16 = 0x0008;
11
12 pub const ECT_MBXPROT_SOE: u16 = 0x0010;
13
14 pub const ECT_MBXPROT_VOE: u16 = 0x0020;
15
16 pub const ECT_COEDET_SDO: u8 = 0x01;
17
18 pub const ECT_COEDET_SDOINFO: u8 = 0x02;
19
20 pub const ECT_COEDET_PDOASSIGN: u8 = 0x04;
21
22 pub const ECT_COEDET_PDOCONFIG: u8 = 0x08;
23
24 pub const ECT_COEDET_UPLOAD: u8 = 0x10;
25
26 pub const ECT_COEDET_SDOCA: u8 = 0x20;
27}
28
29#[derive(Clone, Debug, Default)]
30#[repr(C)]
31pub struct PdoStats {
32 pub read_count: u32,
33 pub write_count: u32,
34 pub error_count: u32,
35 pub total_bytes_read: u32,
36 pub total_bytes_written: u32,
37 pub last_cycle_time_ns: u64,
38 pub min_cycle_time_ns: u64,
39 pub max_cycle_time_ns: u64,
40 pub avg_cycle_time_ns: u64,
41}
42
43#[derive(Clone, Debug)]
44#[repr(C, packed)]
45pub struct PdoMappingEntry {
46 pub index: u16,
47 pub sub_index: u8,
48 pub bit_length: u8,
49 pub bit_offset: u16,
50 pub name: [u8; 64],
51 pub unit: [u8; 16],
52 pub readable: u8,
53 pub writable: u8,
54}
55
56#[derive(Clone, Debug, Default)]
57#[repr(C, packed)]
58pub struct CommunicationStatsLocal {
59 pub total_cycles: u32,
60 pub successful_cycles: u32,
61 pub failed_cycles: u32,
62 pub timeout_cycles: u32,
63 pub average_cycle_time_us: f64,
64 pub max_cycle_time_us: f64,
65 pub min_cycle_time_us: f64,
66}
67
68#[derive(Clone, Debug, Default)]
69pub struct SlaveInfo {
70 pub vendor_id: u32,
71 pub product_code: u32,
72 pub revision_number: u32,
73 pub serial_number: u32,
74 pub device_name: String,
75 pub vendor_name: String,
76 pub sync_manager_count: u16,
77 pub fmmu_count: u16,
78 pub supports_coe: bool,
79 pub supports_foe: bool,
80 pub supports_eoe: bool,
81 pub supports_soe: bool,
82}
83
84#[derive(Clone, Debug, Default)]
85#[repr(C, packed)]
86pub struct RealtimeStats {
87 pub current_cycle_time_us: f64,
88 pub jitter_us: f64,
89 pub lost_frames: u32,
90 pub corrupted_frames: u32,
91 pub bus_utilization: f64,
92}
93
94#[derive(Clone, Debug)]
95#[repr(C, packed)]
96pub struct NetworkInfo {
97
98 pub name: [u8; 128],
99
100 pub desc: [u8; 128],
101
102 pub slave_num: i16,
103
104 pub redundant_slave_num: i16,
105}
106
107#[derive(Clone, Copy, Debug, Default)]
108#[repr(C, packed)]
109pub struct EcSmt {
110
111 pub start_addr: u16,
112
113 pub sm_length: u16,
114
115 pub sm_flags: u32,
116}
117
118#[derive(Clone, Copy, Debug, Default)]
119#[repr(C, packed)]
120pub struct EcFmmut {
121
122 pub log_start: u32,
123
124 pub log_length: u16,
125
126 pub log_start_bit: u8,
127
128 pub log_end_bit: u8,
129
130 pub phys_start: u16,
131
132 pub phys_start_bit: u8,
133
134 pub fmmu_type: u8,
135
136 pub fmmu_active: u8,
137
138 pub unused1: u8,
139
140 pub unused2: u16,
141}
142
143#[derive(Clone, Copy, Debug, Default)]
144#[repr(C)]
145pub struct SlaveIoDesc {
146
147 pub bits: u16,
148
149 pub bytes: u32,
150
151 pub ptr: usize,
152
153 pub offset: u32,
154
155 pub startbit: u8,
156}
157
158#[derive(Clone, Copy, Debug, Default)]
159#[repr(C)]
160pub struct SlaveFsoe {
161
162 pub capable: u8,
163
164 pub connection: usize,
165
166 pub sm_context: usize,
167
168 pub connection_id: u16,
169
170 pub safety_address: u16,
171
172 pub safe_input_size: u16,
173
174 pub safe_output_size: u16,
175
176 pub pdo_input_offset: u32,
177
178 pub pdo_output_offset: u32,
179}
180
181#[derive(Clone, Copy, Debug, Default)]
182#[repr(C)]
183pub struct SlaveMailbox {
184
185 pub length: u16,
186
187 pub write_offset: u16,
188
189 pub read_length: u16,
190
191 pub read_offset: u16,
192
193 pub supported_proto: u16,
194
195 pub cnt: u8,
196}
197
198#[derive(Clone, Copy, Debug, Default)]
199#[repr(C)]
200pub struct SlaveEepromConfig {
201
202 pub _reserved_sii: u16,
203
204 pub read_8byte: u8,
205
206 pub pdi: u8,
207}
208
209#[derive(Clone, Copy, Debug, Default)]
210#[repr(C)]
211pub struct SlaveHandler {
212
213 pub state: i32,
214
215 pub rmp_state: i32,
216
217 pub instate_ex: u16,
218}
219
220#[derive(Clone, Copy, Debug, Default)]
221#[repr(C)]
222pub struct SlaveIdentity {
223
224 pub vendor_id: u32,
225
226 pub product_id: u32,
227
228 pub revision: u32,
229
230 pub serial: u32,
231
232 pub itype: u16,
233
234 pub dtype: u16,
235}
236
237#[derive(Clone, Copy, Debug)]
238#[repr(C)]
239pub struct SlaveMetadata {
240
241 pub identity: SlaveIdentity,
242
243 pub group_name: [u8; 41],
244
245 pub device_name: [u8; 41],
246
247 pub sm_count: u16,
248}
249
250impl Default for SlaveMetadata {
251 fn default() -> Self {
252 Self {
253 identity: SlaveIdentity::default(),
254 group_name: [0; 41],
255 device_name: [0; 41],
256 sm_count: 0,
257 }
258 }
259}
260
261#[derive(Clone, Copy, Debug, Default)]
262#[repr(C)]
263pub struct SlaveCapabilities {
264
265 pub is_optional: u8,
266
267 pub supports_frame_repeat: u8,
268
269 pub mailbox_side: u8,
270
271 pub coe_details: u8,
272
273 pub foe_details: u8,
274
275 pub eoe_details: u8,
276
277 pub soe_details: u8,
278}
279
280#[derive(Clone, Copy, Debug, Default)]
281#[repr(C)]
282pub struct SlaveRuntime {
283
284 pub ebus_current: i16,
285
286 pub block_lrw: u8,
287
288 pub group: u8,
289
290 pub is_lost: u8,
291}
292
293#[derive(Clone, Copy, Debug, Default)]
294#[repr(C)]
295pub struct SlaveSmFmmu {
296
297 pub sm_type: [u8; 8],
298
299 pub sm_app_length: [u16; 8],
300
301 pub fmmu_func: [u8; 4],
302
303 pub fmmu_unused: u8,
304}
305
306#[derive(Clone, Copy, Debug, Default)]
307#[repr(C)]
308pub struct SlaveProtoMbx {
309
310 pub in_ptr: usize,
311
312 pub in_full: u8,
313
314 pub overrun: i32,
315}
316
317#[derive(Clone, Copy, Debug, Default)]
318#[repr(C)]
319pub struct SlavePdoConfig {
320
321 pub assignment_enabled: u8,
322
323 pub configuration_enabled: u8,
324
325 pub config_initialized: u8,
326
327 pub supports_complete_access: u8,
328}
329
330#[derive(Clone, Copy, Debug, Default)]
331#[repr(C)]
332pub struct SlaveTopology {
333
334 pub has_dc: u8,
335
336 pub phy_type: u8,
337
338 pub link_count: u8,
339
340 pub active_ports: u8,
341
342 pub consumed_ports: u8,
343
344 pub parent: u16,
345
346 pub parent_port: u8,
347
348 pub entry_port: u8,
349}
350
351#[derive(Clone, Copy, Debug, Default)]
352#[repr(C)]
353pub struct SlaveDc {
354
355 pub recvtime: [i32; 4],
356
357 pub propagation_delay: i32,
358
359 pub next: u16,
360
361 pub prev: u16,
362
363 pub cycle0: i32,
364
365 pub cycle1: i32,
366
367 pub shift: i32,
368
369 pub active: u16,
370}
371
372#[derive(Clone, Debug)]
373#[repr(C)]
374pub struct EcSlave {
375
376 pub state: u16,
377
378 pub al_status_code: u16,
379
380 pub config_addr: u16,
381
382 pub alias_addr: u16,
383
384 pub fsoe: SlaveFsoe,
385
386 pub output: SlaveIoDesc,
387
388 pub input: SlaveIoDesc,
389
390 pub sm: [EcSmt; 8],
391
392 pub fmmu: [EcFmmut; 4],
393
394 pub sm_fmmu: SlaveSmFmmu,
395
396 pub mbx: SlaveMailbox,
397
398 pub topo: SlaveTopology,
399
400 pub dc: SlaveDc,
401
402 pub eeprom_config: SlaveEepromConfig,
403
404 pub runtime: SlaveRuntime,
405
406 pub po2so_config: usize,
407
408 pub handler: SlaveHandler,
409
410 pub coe: SlaveProtoMbx,
411
412 pub soe: SlaveProtoMbx,
413
414 pub foe: SlaveProtoMbx,
415
416 pub eoe: SlaveProtoMbx,
417
418 pub voe: SlaveProtoMbx,
419
420 pub aoe: SlaveProtoMbx,
421
422 pub mbx_status: usize,
423
424 pub metadata: SlaveMetadata,
425
426 pub pdo_config: SlavePdoConfig,
427
428 pub capabilities: SlaveCapabilities,
429}
430
431#[derive(Clone, Debug)]
432#[repr(C)]
433pub struct EcState {
434
435 pub state: u16,
436
437 pub al_status_code: u16,
438
439 pub slave_count: i32,
440
441 pub loop_cycle: u32,
442
443 pub dc_cycle: u32,
444
445 pub dc_time: i64,
446
447 pub iomap: [u8; 65536],
448
449 pub iomap_mutex: usize,
450
451 pub iomap_buffer: [u8; 65536],
452
453 pub buffer_version: u32,
454
455 pub buffer_dirty: u8,
456
457 pub mutex_protection: u8,
458
459 pub pdo_cpu_affinity: i8,
460
461 pub dc_auto_shift_enabled: u8,
462
463 pub use_udp: u8,
464
465 pub adaptive_timeout_enabled: u8,
466
467 pub overlapping_groups: u8,
468
469 pub packed_mode: u8,
470
471 pub frame_high_priority: u8,
472
473 pub vlan_id: u16,
474
475 pub vlan_priority: u8,
476
477 pub timeout_init_to_preop: u32,
478
479 pub timeout_preop_to_safeop: u32,
480
481 pub timeout_safeop_to_op: u32,
482
483 pub wd_pd_timeout_ms: u16,
484
485 pub wd_pdi_timeout_ms: u16,
486
487 pub filter_threshold: u32,
488
489 pub frame_repeat_count: u8,
490
491 pub active_group_count: u8,
492
493 pub _group_pad: [u8; 2],
494
495 pub group_config_raw: [u8; 160],
496}
497
498#[derive(Clone, Debug)]
499#[repr(C)]
500pub struct InternalDiagnostics {
501
502 pub cache_cnt: u32,
503
504 pub rt_cnt: u32,
505
506 pub cycle_count: u32,
507
508 pub error_cache_cnt: u32,
509
510 pub error_cnt: u32,
511
512 pub wkc: u16,
513
514 pub expected_wkc: u16,
515
516 pub cycle_time_span: u32,
517
518 pub frame_errors: u32,
519
520 pub lost_frames: u32,
521
522 pub checksum_errors: u32,
523
524 pub timeout_frames: u32,
525
526 pub rx_error_count: [u32; 512],
527
528 pub tx_error_count: [u32; 512],
529
530 pub lost_link_count: [u16; 512],
531
532 pub invalid_frame_count: [u16; 512],
533
534 pub working_counter_errors: u16,
535
536 pub consecutive_wkc_errors: u16,
537
538 pub total_wkc_mismatches: u32,
539
540 pub cycle_start_time: u64,
541
542 pub cycle_time_accumulator: f64,
543
544 pub last_snapshot_time: u64,
545
546 pub snapshot_cycle_count: u32,
547
548 pub last_cycle_time_us: f64,
549
550 pub jitter_accumulator: f64,
551
552 pub max_jitter_in_second: f64,
553
554 pub jitter_sample_count: u32,
555
556}
557
558#[derive(Clone, Debug)]
559pub struct FoEOptionsLocal {
560
561 pub enable_crc: bool,
562
563 pub strict_mode: bool,
564
565 pub auto_append_crc: bool,
566
567 pub expected_crc: u32,
568}
569
570impl Default for FoEOptionsLocal {
571 fn default() -> Self {
572 Self {
573 enable_crc: false,
574 strict_mode: true,
575 auto_append_crc: true,
576 expected_crc: 0,
577 }
578 }
579}
580
581pub struct EcGroupConfigHelper;
582
583impl EcGroupConfigHelper {
584
585 const GROUP_CONFIG_SIZE: usize = 20;
586
587 pub fn get_group_enabled(raw: &[u8], group: u8) -> bool {
588 if group >= 8 { return false; }
589 raw[group as usize * Self::GROUP_CONFIG_SIZE] != 0
590 }
591
592 pub fn set_group_enabled(raw: &mut [u8], group: u8, enabled: bool) {
593 if group >= 8 { return; }
594 raw[group as usize * Self::GROUP_CONFIG_SIZE] = if enabled { 1 } else { 0 };
595 }
596
597 pub fn get_group_cycle_divider(raw: &[u8], group: u8) -> u8 {
598 if group >= 8 { return 0; }
599 raw[group as usize * Self::GROUP_CONFIG_SIZE + 1]
600 }
601
602 pub fn set_group_cycle_divider(raw: &mut [u8], group: u8, divider: u8) {
603 if group >= 8 { return; }
604 raw[group as usize * Self::GROUP_CONFIG_SIZE + 1] = divider;
605 }
606
607 pub fn get_group_expected_wkc(raw: &[u8], group: u8) -> u16 {
608 if group >= 8 { return 0; }
609 let off = group as usize * Self::GROUP_CONFIG_SIZE + 2;
610 u16::from_le_bytes([raw[off], raw[off + 1]])
611 }
612
613 pub fn get_group_slave_count(raw: &[u8], group: u8) -> u16 {
614 if group >= 8 { return 0; }
615 let off = group as usize * Self::GROUP_CONFIG_SIZE + 4;
616 u16::from_le_bytes([raw[off], raw[off + 1]])
617 }
618
619 pub fn get_group_frame_repeat_eligible(raw: &[u8], group: u8) -> bool {
620 if group >= 8 { return false; }
621 raw[group as usize * Self::GROUP_CONFIG_SIZE + 6] != 0
622 }
623
624 pub fn set_group_frame_repeat_eligible(raw: &mut [u8], group: u8, eligible: bool) {
625 if group >= 8 { return; }
626 raw[group as usize * Self::GROUP_CONFIG_SIZE + 6] = if eligible { 1 } else { 0 };
627 }
628
629 pub fn get_group_actual_wkc(raw: &[u8], group: u8) -> u16 {
630 if group >= 8 { return 0; }
631 let off = group as usize * Self::GROUP_CONFIG_SIZE + 8;
632 u16::from_le_bytes([raw[off], raw[off + 1]])
633 }
634
635 pub fn get_group_consecutive_miss(raw: &[u8], group: u8) -> u16 {
636 if group >= 8 { return 0; }
637 let off = group as usize * Self::GROUP_CONFIG_SIZE + 10;
638 u16::from_le_bytes([raw[off], raw[off + 1]])
639 }
640
641 pub fn get_group_total_frames(raw: &[u8], group: u8) -> u32 {
642 if group >= 8 { return 0; }
643 let off = group as usize * Self::GROUP_CONFIG_SIZE + 12;
644 u32::from_le_bytes([raw[off], raw[off + 1], raw[off + 2], raw[off + 3]])
645 }
646
647 pub fn get_group_mismatch_frames(raw: &[u8], group: u8) -> u32 {
648 if group >= 8 { return 0; }
649 let off = group as usize * Self::GROUP_CONFIG_SIZE + 16;
650 u32::from_le_bytes([raw[off], raw[off + 1], raw[off + 2], raw[off + 3]])
651 }
652}