# CATio Architecture Overview
CATio is a Python-based control system integration for EtherCAT I/O devices running under Beckhoff TwinCAT. The architecture is deliberately designed with a clean separation between two halves:
1. **FastCS EPICS IOC Layer** - Exposes Process Variables (PVs) for controlling EtherCAT devices
2. **ADS Client Layer** - Communicates with TwinCAT ADS servers on Beckhoff PLCs
## High-Level Architecture Diagram
```mermaid
flowchart TB
clients["EPICS Clients / Control Systems"]
subgraph fastcs["FastCS EPICS IOC Layer"]
direction LR
server["CATioServerController"] --> device["CATioDeviceController
(EtherCAT Master)"] --> terminal["Dynamic Terminal Controllers
(generated from YAML)"]
fastcs_files["catio_controller.py
catio_dynamic_controller.py
catio_dynamic_symbol.py
catio_dynamic_coe.py"]
end
subgraph yamldef["Terminal Definitions"]
direction LR
yaml["terminal_types.yaml"] --> dynamic["get_terminal_controller_class()"]
runtime["runtime_symbols.yaml"] --> dynamic
end
subgraph bridge["CATio API Bridge"]
direction LR
conn["CATioConnection"] --> stream["CATioStreamConnection"] --> adsbridge["AsyncioADSClient"]
bridge_files["catio_connection.py"]
end
subgraph adslayer["ADS Client Layer"]
direction LR
adsclient["AsyncioADSClient
Route management (UDP)
TCP connection handling
AMS message send/receive
I/O introspection
Symbol management
Notification subscriptions
API query/command dispatch"]
ads_files["client.py, messages.py
devices.py, symbols.py"]
end
subgraph twincat["TwinCAT ADS Server"]
direction LR
ioserver["I/O Server
(Port 300)"] --> master["EtherCAT Master
(Port 65535)"] --> slaves["EtherCAT Slaves
(EK/EL modules)"]
end
clients -->|"Channel Access / PVAccess"| fastcs
yamldef -->|"Controller classes"| fastcs
fastcs -->|"CATioConnection API
(CATioFastCSRequest/Response)"| bridge
bridge -->|"ADS Protocol (TCP/UDP)"| adslayer
adslayer -->|"ADS/AMS Protocol
(TCP 48898, UDP 48899)"| twincat
```
## Component Overview
### FastCS EPICS IOC Layer
The top layer provides EPICS integration through the FastCS framework:
- **CATioServerController**: Root controller representing the I/O server; manages TCP connections and device discovery
- **CATioDeviceController**: Represents EtherCAT Master devices with their associated attributes
- **Dynamic Terminal Controllers**: Generated at runtime from YAML terminal definitions (see below)
- **CATioControllerAttributeIO**: Handles attribute read/write operations through the API
### Dynamic Controller Generation
Terminal controllers are generated dynamically from YAML definitions in `src/catio_terminals/terminals/`:
- **`get_terminal_controller_class()`**: Factory function that creates controller classes on demand
- **`catio_dynamic_controller.py`**: Creates FastCS controller classes from YAML terminal type definitions
- **`catio_dynamic_symbol.py`**: Adds PDO symbol attributes (process data) to controllers
- **`catio_dynamic_coe.py`**: Adds CoE parameter attributes (configuration) to controllers
- **`catio_dynamic_types.py`**: Type conversion between TwinCAT, numpy, and FastCS types
Controller classes are cached so only one class is created per terminal type:
```python
from fastcs_catio.catio_dynamic_controller import get_terminal_controller_class
# Get or create a controller class for a terminal type
controller_class = get_terminal_controller_class("EL1004")
# Use it like any other controller class
controller = controller_class(name="MOD1", node=node)
```
### API Bridge Layer
The middle layer provides a clean interface between FastCS and the ADS client:
- **CATioConnection**: Singleton managing the TCP connection lifecycle
- **CATioStreamConnection**: Wraps the ADS client with async context management
- **CATioFastCSRequest/Response**: Request/response objects for API communication
### ADS Client Layer
The bottom layer implements the TwinCAT ADS protocol:
- **AsyncioADSClient**: Asynchronous ADS client handling all protocol communication
- **RemoteRoute**: UDP-based route management for network discovery
- **Message classes**: Structured ADS message types for various commands
- **Device/Symbol models**: Data classes representing EtherCAT hardware and ADS symbols
## Data Flow
### Initialization Flow
1. **Route Discovery**: UDP communication discovers the remote TwinCAT server's AMS NetId
2. **Route Addition**: Client machine is added to the TwinCAT server's routing table
3. **TCP Connection**: Establish persistent TCP connection for ADS communication
4. **I/O Introspection**: Query server for devices, slaves, and symbol information
5. **Dynamic Controller Creation**: Generate controller classes from YAML definitions based on discovered terminal types
6. **Attribute Registration**: Create EPICS PVs for each accessible parameter (symbols and CoE objects)
### Runtime Data Flow
```mermaid
sequenceDiagram
participant Client as EPICS Client
participant FastCS as FastCS Attribute
participant IO as CATioControllerAttributeIO
participant Conn as CATioConnection
participant ADS as AsyncioADSClient
participant TC as TwinCAT Server
Client->>FastCS: Read/Write PV
FastCS->>IO: update()
IO->>Conn: send_query()
Conn->>ADS: query() / command()
ADS->>ADS: API method dispatch (get_* / set_*)
ADS->>TC: ADS Read/Write/ReadWrite
TC-->>ADS: Response
ADS-->>Conn: Response
Conn-->>IO: Response
IO-->>FastCS: Update attribute
FastCS-->>Client: PV updated
```
## Key Design Decisions
### Dynamic Controller Generation
Terminal controllers are generated from YAML definitions rather than explicit Python classes:
- **Flexibility**: New terminal types can be added by editing YAML without code changes
- **Maintainability**: Single source of truth for terminal definitions in `terminal_types.yaml`
- **Runtime symbols**: Diagnostic symbols from the EtherCAT master defined separately in `runtime_symbols.yaml`
- **Selection**: Only symbols marked `selected: true` in YAML become FastCS attributes
### Asynchronous Architecture
The entire stack uses Python's `asyncio` for non-blocking I/O operations:
- Enables concurrent handling of multiple PV requests
- Supports continuous notification monitoring without blocking
- Allows efficient polling of device states
### Controller Hierarchy
Controllers form a tree structure mirroring the physical EtherCAT topology:
```
IOServer
└── IODevice (EtherCAT Master)
├── IOSlave (EK1100 Coupler)
│ ├── IOSlave (EL3xxx Input) - DynamicEL3xxxController
│ └── IOSlave (EL4xxx Output) - DynamicEL4xxxController
└── IOSlave (EK1101 Coupler)
└── ...
```
### Symbol-Based Access
ADS symbols provide named access to device parameters rather than raw memory addresses:
- Symbols discovered during introspection
- Notification subscriptions for efficient updates
- Type information preserved for proper data conversion
## Configuration
CATio is configured through command-line parameters:
- **target_ip**: IP address of the Beckhoff PLC
- **target_port**: AMS port for the I/O device (typically 851 for TwinCAT)
- **poll_period**: Interval for standard attribute polling
- **notification_period**: Interval for processing ADS notifications
## See Also
- [FastCS EPICS IOC Implementation](fastcs-epics-ioc.md) - Details of the EPICS layer
- [ADS Client Implementation](ads-client.md) - Details of the ADS protocol layer
- [Terminal YAML Definitions](terminal-yaml-definitions.md) - How to define terminal types in YAML
- [API Decoupling Analysis](decisions/0003-api-decoupling-analysis.md) - Discussion of the API design and potential improvements