APIs, concepts, guides, and more
Network: Status

Learn how to read and display network and node status diagnostics from an EtherCAT network. The application creates a MotionController object, checks for errors, and displays overall network status along with per-node AL Status, status codes, and CoE emergency messages.

Warning
This is a sample program to assist in the integration of the RMP motion controller with your application. It may not contain all of the logic and safety features that your application requires. We recommend that you wire an external hardware emergency stop (e-stop) button for safety when using our code sample apps. Doing so will help ensure the safety of you and those around you and will prevent potential injury or damage.

The sample apps assume that the system (network, axes, I/O) are configured prior to running the code featured in the sample app. See the Configuration page for more information.


In this page:


📜 Network Status

""" EtherCAT network status diagnostic utility for real-time monitoring.
This utility displays the overall network status from the MotionController and
the individual status of each network node. It provides visibility into:
Network Status (MotionController level):
- ActiveNodeCount: Number of nodes actively responding on the network
- AlStatus: Logical OR of AL Status registers from all nodes (0x0130)
- MissedCyclicFrameCount: Cumulative count of missed cyclic EtherCAT frames
- CyclicFramePeriodUs: Most recent cyclic frame period in microseconds
- SynchronizationErrorNs: Distributed Clock synchronization error in nanoseconds
Node Status (per RapidCodeNetworkNode):
- AlStatus: EtherCAT AL Status register (0x0130) value for this specific node
- AlStatusCode: EtherCAT AL Status Code register value (error details)
- CoeEmergencyMessage: CANopen over EtherCAT emergency message (if any)
- CoeEmergencyMessageNetworkCounter: Network counter when emergency was received
AL Status Register (0x0130) Decoding:
Bits 0-3 indicate Device State Machine state:
- 1 = Init (initialization)
- 2 = PreOp (pre-operational, mailbox communication only)
- 3 = Bootstrap (firmware update mode)
- 4 = SafeOp (safe-operational, inputs active, outputs safe)
- 8 = Operational (full operation, inputs and outputs active)
Bit 4 is the Error Flag - when set, check AlStatusCode for details.
When to Use This Diagnostic Tool:
- Verify all nodes are in OPERATIONAL state after network startup
- Check for nodes reporting errors (Bit 4 set in AlStatus)
- Monitor missed cyclic frame counts for network quality issues
- Check DC synchronization error for timing accuracy
- Diagnose CoE emergency messages from drives or devices
Practical Examples of Output to Diagnose Network Issues:
Example 1: A cable or power failure.
- Active Node Count: 2 (7 discovered)
Example 2: A node fell out of Operational state. Look up 1A in the manual.
- 0 | Mitsubishi MR-J5-TM | 0x14 (SAFEOP+ERR) | 0x001A | 0x000000000000 | 0
"""
from _imports import RapidCode, helpers
# AL Status state decoding (bits 0-3)
AL_STATUS_STATES = {
0x01: "INIT",
0x02: "PREOP",
0x03: "BOOT",
0x04: "SAFEOP",
0x08: "OP",
}
ERROR_SUFFIX = "+ERR"
# Calculate formatting widths from actual data
MAX_STATE_WIDTH = max(len(s) for s in AL_STATUS_STATES.values()) + len(ERROR_SUFFIX) # e.g., "SAFEOP" + "+ERR" = 10
AL_STATUS_COL_WIDTH = 7 + MAX_STATE_WIDTH # "0xXX (" + state + ")" = 7 + state width
def decode_al_status(al_status: int) -> str:
"""Decode AL Status register to human-readable state (single node)."""
state = al_status & 0x0F # bits 0-3
error_flag = (al_status & 0x10) != 0 # bit 4
state_name = AL_STATUS_STATES.get(state, "?")
if error_flag:
state_name += ERROR_SUFFIX
return state_name
def decode_al_status_ored(al_status: int) -> str:
"""Decode ORed AL Status (network-level, multiple nodes).
When AL Status values from multiple nodes are ORed together,
we check individual bits. Note: BOOT(3) = INIT(1)|PREOP(2), so
we can't distinguish BOOT from INIT+PREOP when ORed.
"""
state_bits = al_status & 0x0F # bits 0-3
error_flag = (al_status & 0x10) != 0 # bit 4
# Check individual bits (only single-bit states are unambiguous when ORed)
states_present = []
if state_bits & 0x01:
states_present.append("INIT")
if state_bits & 0x02:
states_present.append("PREOP")
if state_bits & 0x04:
states_present.append("SAFEOP")
if state_bits & 0x08:
states_present.append("OP")
if states_present:
state_name = "|".join(states_present)
else:
state_name = "NONE"
if error_flag:
state_name += ERROR_SUFFIX
return state_name
def display_network_status(controller: RapidCode.MotionController):
"""Display the overall network status and per-node status."""
# Get network status from MotionController
network_status = controller.NetworkStatusGet()
# Collect nodes and determine max name length for formatting
nodes = []
max_name_len = 10 # minimum width
for i in range(controller.NetworkNodeCountGet()):
node = controller.NetworkNodeGet(i)
helpers.check_errors(node)
if node.Exists():
nodes.append(node)
max_name_len = max(max_name_len, len(node.NameGet()))
# Print network status header
width = 80
print("\n" + "=" * width)
print("NETWORK STATUS")
print("=" * width)
# Decode and display network-level status
network_state = helpers.get_enum_name("RSINetworkState_RSINetworkState", controller.NetworkStateGet())
al_status_str = f"0x{network_status.AlStatus:02X} ({decode_al_status_ored(network_status.AlStatus)})"
sync_sign = "+" if network_status.SynchronizationErrorNs >= 0 else ""
print(f" Network State: {network_state}")
print(f" Active Node Count: {network_status.ActiveNodeCount} ({controller.NetworkNodeCountGet()} discovered)")
print(f" AL Status: {al_status_str}")
print(f" Missed Cyclic Frames: {network_status.MissedCyclicFrameCount}")
print(f" Cyclic Frame Period: {network_status.CyclicFramePeriodUs} us")
print(f" Synchronization Error: {sync_sign}{network_status.SynchronizationErrorNs} ns")
# Print per-node status
print("\n" + "=" * width)
print("NODE STATUS")
print("=" * width)
# Header row
header = f"{'Node':>4} | {'Name':<{max_name_len}} | {'AL Status':^{AL_STATUS_COL_WIDTH}} | {'AL Code':^8} | {'CoE Emergency':^16} | {'Counter':>8}"
print(header)
print("-" * len(header))
# Print each node's status
for node in nodes:
node_index = node.NumberGet()
node_name = node.NameGet()[:max_name_len]
# Get node status
status = node.StatusGet()
# Format fields
al_status_str = f"0x{status.AlStatus:02X} ({decode_al_status(status.AlStatus):^{MAX_STATE_WIDTH}})"
al_code_str = f"0x{status.AlStatusCode:04X}"
coe_emergency_str = f"0x{status.CoeEmergencyMessage:012X}"
counter_str = f"{status.CoeEmergencyMessageNetworkCounter:8d}"
print(f"{node_index:>4} | {node_name:<{max_name_len}} | {al_status_str:^{AL_STATUS_COL_WIDTH}} | {al_code_str:^8} | {coe_emergency_str:^16} | {counter_str}")
print("=" * width)
# MAIN
print("Network Status Diagnostic")
print("-" * 40)
# Create motion controller
creation_params: RapidCode.CreationParameters = helpers.get_creation_parameters()
motion_controller: RapidCode.MotionController = RapidCode.MotionController.Create(creation_params)
# Check for errors
print(f"MotionController creation error count: {motion_controller.ErrorLogCountGet()}")
helpers.check_errors(motion_controller)
# Print version info
print(f"RapidCode Version: {motion_controller.VersionGet()}")
print(f"Serial Number: {motion_controller.SerialNumberGet()}")
# Display network and node status
display_network_status(motion_controller)
# Clean up
motion_controller.Delete()