1""" EtherCAT RX error counter diagnostic utility for real-time network quality monitoring.
2
3 This utility reads the mandatory EtherCAT RX Error Counters from all network nodes following
4 the EtherCAT Technology Group diagnostic specifications. It monitors communication quality by
5 tracking both Frame Errors (CRC failures at data link layer) and Physical Layer Errors
6 (invalid symbols at hardware level) for each slave port.
7
8 RX Error Counter Types (Per ETG.1600)
9 - Frame Error Counters (0x0300, 0x0302, 0x0304, 0x0306): Increment when CRC check fails on
10 incoming frames, indicating corrupted data that will be discarded. Each slave port checks
11 frames arriving from outside and increments this counter when corruption is detected.
12 - Physical Layer Error Counters (0x0301, 0x0303, 0x0305, 0x0307): Track invalid symbols
13 detected at the physical layer, can occur both within and outside frames. When occurring
14 within frames, usually indicates Frame Errors as well.
15
16 When to Use This Diagnostic Tool
17 - Lost Frame Counter increments at master - investigate with this tool
18 - Working Counter (WKC) errors detected - deeper hardware diagnosis needed
19 - Cable qualification - validate new installations meet industrial Ethernet standards
20 - EMC troubleshooting - sporadic errors indicate electromagnetic interference
21 - Preventive maintenance - periodic monitoring for degrading connections
22
23 Interpreting Error Counter Values
24 - All zeros: Ideal state, network operating perfectly
25 - Sporadic increments (days/weeks apart): Normal due to BER 10^-12 (one bit error per trillion bits transmitted).
26 Industrial Ethernet standard.
27 - Burst errors (seconds/minutes): Actual problem requiring investigation
28 - Systematic increment: Hardware failure (damaged cable, connector oxidation, device fault)
29 - Unbalanced counters: Many Physical Layer but no Frame Errors or vice versa may indicate internal device
30 issue - consider replacing the device
31
32 Diagnostic Procedure (ETG Standard)
33 1. Follow frame path through network topology
34 2. Find FIRST port reporting Frame Error ≠ 0 in path sequence
35 3. Problem location is between this port and previous device
36 4. Check: cable routing near power lines, connector quality, shielding, grounding
37
38 Per ETG specifications, errors immediately after power-on/off are expected and should
39 be ignored. Only errors during steady-state operation indicate actual problems.
40
41 See also: ServiceChannelRead() can read ESC registers (< 0x1000) and SDOs (>= 0x1000)
42"""
43
44from typing import Dict
45from _imports import RapidCode, helpers
46
47
48
49PORT_0_FRAME_ERROR_COUNTER_REG = 0x300
50PORT_0_RX_ERROR_COUNTER_REG = 0x301
51PORT_1_FRAME_ERROR_COUNTER_REG = 0x302
52PORT_1_RX_ERROR_COUNTER_REG = 0x303
53PORT_2_FRAME_ERROR_COUNTER_REG = 0x304
54PORT_2_RX_ERROR_COUNTER_REG = 0x305
55PORT_3_FRAME_ERROR_COUNTER_REG = 0x306
56PORT_3_RX_ERROR_COUNTER_REG = 0x307
57ERROR_COUNT_SUBINDEX = 0
58ERROR_COUNT_BYTES = 1
59
60
61
62def read_node_rx_error_counters(node) -> Dict[str, int]:
63 """Read all RX error counters from a network node."""
64 error_counts = {}
65
66 try:
67
68 error_counts['Port0_FrameErrors'] = node.ServiceChannelRead(PORT_0_FRAME_ERROR_COUNTER_REG, ERROR_COUNT_SUBINDEX, ERROR_COUNT_BYTES)
69 error_counts['Port0_RxErrors'] = node.ServiceChannelRead(PORT_0_RX_ERROR_COUNTER_REG, ERROR_COUNT_SUBINDEX, ERROR_COUNT_BYTES)
70
71
72 error_counts['Port1_FrameErrors'] = node.ServiceChannelRead(PORT_1_FRAME_ERROR_COUNTER_REG, ERROR_COUNT_SUBINDEX, ERROR_COUNT_BYTES)
73 error_counts['Port1_RxErrors'] = node.ServiceChannelRead(PORT_1_RX_ERROR_COUNTER_REG, ERROR_COUNT_SUBINDEX, ERROR_COUNT_BYTES)
74
75
76 error_counts['Port2_FrameErrors'] = node.ServiceChannelRead(PORT_2_FRAME_ERROR_COUNTER_REG, ERROR_COUNT_SUBINDEX, ERROR_COUNT_BYTES)
77 error_counts['Port2_RxErrors'] = node.ServiceChannelRead(PORT_2_RX_ERROR_COUNTER_REG, ERROR_COUNT_SUBINDEX, ERROR_COUNT_BYTES)
78
79
80 error_counts['Port3_FrameErrors'] = node.ServiceChannelRead(PORT_3_FRAME_ERROR_COUNTER_REG, ERROR_COUNT_SUBINDEX, ERROR_COUNT_BYTES)
81 error_counts['Port3_RxErrors'] = node.ServiceChannelRead(PORT_3_RX_ERROR_COUNTER_REG, ERROR_COUNT_SUBINDEX, ERROR_COUNT_BYTES)
82
83 except Exception as ex:
84 print(f"Error reading node {node.NumberGet()}: {ex}")
85
86 for port in range(4):
87 error_counts[f'Port{port}_FrameErrors'] = 0
88 error_counts[f'Port{port}_RxErrors'] = 0
89
90 return error_counts
91
92def display_network_error_diagnostics(controller: RapidCode.MotionController):
93 """Display RX error diagnostic counters for all nodes in the network."""
94
95
96 nodes = []
97 max_node_name_length = 10
98 for i in range(controller.NetworkNodeCountGet()):
99 io = controller.IOGet(i)
100 helpers.check_errors(io)
101 if io.NetworkNode.Exists():
102 nodes.append(io.NetworkNode)
103 max_node_name_length = max(max_node_name_length, len(io.NetworkNode.NameGet()))
104
105
106 header_line = f"{'Node':^4} | {'Name':^{max_node_name_length}} | {'Port 0':^12} | {'Port 1':^12} | {'Port 2':^12} | {'Port 3':^12}"
107 subheader_line = f"{'':^4} | {'':^{max_node_name_length}} | {'Frame RX':^12} | {'Frame RX':^12} | {'Frame RX':^12} | {'Frame RX':^12}"
108
109
110 total_width = len(header_line)
111
112 print("\n" + "="*total_width)
113 print("ETHERCAT RX ERROR COUNTERS")
114 print(f"Network: {controller.NetworkNodeCountGet()} Nodes")
115 print("="*total_width)
116
117
118 print(header_line)
119 print(subheader_line)
120 print("-"*total_width)
121
122
123 for node in nodes:
124 node_index = node.NumberGet()
125 node_name = node.NameGet()[:max_node_name_length]
126
127
128 error_counts = read_node_rx_error_counters(node)
129
130
131 ports = []
132 for port_num in range(4):
133 frame_errors = error_counts[f'Port{port_num}_FrameErrors']
134 rx_errors = error_counts[f'Port{port_num}_RxErrors']
135 ports.append(f"{frame_errors:5d} {rx_errors:5d}")
136
137 print(f"{node_index:^4} | {node_name:<{max_node_name_length}} | {ports[0]:^12} | {ports[1]:^12} | {ports[2]:^12} | {ports[3]:^12}")
138
139 print("="*total_width)
140
141
142
143print("⬤ NetworkNode Errors")
144
145print("EtherCAT RX Error Counter Diagnostics")
146print("-"*40)
147
148
149creation_params: RapidCode.CreationParameters = helpers.get_creation_parameters()
150motion_controller: RapidCode.MotionController = RapidCode.MotionController.Create(creation_params)
151
152
153print(f"MotionController creation error count: {motion_controller.ErrorLogCountGet()}")
154helpers.check_errors(motion_controller)
155
156
157print(f"RapidCode Version: {motion_controller.VersionGet()}")
158print(f"Serial Number: {motion_controller.SerialNumberGet()}")
159
160
161if motion_controller.NetworkStateGet() == RapidCode.RSINetworkState_RSINetworkStateOPERATIONAL:
162 display_network_error_diagnostics(motion_controller)
163else:
164 print("\nNetwork is not in OPERATIONAL state. Current state:", motion_controller.NetworkStateGet())
165 print("Cannot read node error counts.")
166
167
168motion_controller.Delete()