- A lightweight, efficient EtherCAT master/slave stack for embedded systems
-
-
-
- Kick-start your slaves! ⚡
+ A lightweight, efficient EtherCAT master/slave stack for embedded and real-time systems
---
## Overview
-KickCAT is a thin EtherCAT stack designed to be embedded in complex software with efficiency in mind. It provides both **master** and **slave** implementations, supporting multiple operating systems and hardware platforms.
-
-**Key Features:**
-- Works with Linux (including RT-PREEMPT), Windows, and PikeOS
-- Full state machine support (INIT → PRE-OP → SAFE-OP → OP)
-- CoE (CANopen over EtherCAT) support with SDO read/write
-- CoE: SDO Information
-- Interface redundancy
-- Bus diagnostics and error handling
-- Master side python bindings
-- Built-in ESC emulator for testing without hardware
-
----
-
-## Quick Start
-
-### Prerequisites
-
-- **Linux**: gcc, cmake, conan (for dependencies)
-- **Python bindings**: uv or pip
-- **Hardware**: Network interface with raw socket access capabilities
-
-### Build and Install
-
-#### Linux (Recommended)
-
-```bash
-# 1. Configure build options (optional — defaults are sensible)
-./scripts/configure.sh build --with=unit_tests
-
-# 2. Setup build environment (installs Conan deps + runs CMake)
-./scripts/setup_build.sh build
-
-# 3. Build
-cd build && make
-
-# 4. Grant network capabilities (required for raw socket access)
-sudo setcap 'cap_net_raw,cap_net_admin=+ep' ./tools/your_binary
-```
-
-#### Python Bindings
-
-```bash
-# Install with uv (recommended)
-uv pip install .
-
-# Or for development (faster rebuilds)
-uv pip install --no-build-isolation -Cbuild-dir=/tmp/build -v .
-```
-
-The wheel build enables the EEPROM-editor GUI (`BUILD_EEPROM_EDITOR=ON` in
-`pyproject.toml`), which needs `imgui` and `glfw`. The cibuildwheel images provide
-them; on a bare environment that lacks them, either install them (via conan) or
-disable the GUI for the build:
-
-```bash
-uv pip install --config-setting=cmake.define.BUILD_EEPROM_EDITOR=OFF .
-```
-
-#### Multi wheel (CI)
-This project use cibuildwheel to generate multiples wheel to support all configurations. To use it locally, call:
-```bash
-uvx cibuildwheel
-```
-
-
-Manual Build Setup
-
-```bash
-# 1. Create build directory
-mkdir -p build
-
-# 2. Install dependencies with conan
-python3 -m venv kickcat_venv
-source kickcat_venv/bin/activate
-pip install conan
-
-conan install conan/conanfile.py -of=build/ \
- -pr:h conan/your_profile_host.txt \
- -pr:b conan/your_profile_target.txt \
- --build=missing -s build_type=Release
-
-# Or create the conan package directly
-conan create conan/all --build=missing --version 2.5 -pr build/profile.txt
-
-# 3. Configure and build
-cd build
-cmake .. -DCMAKE_BUILD_TYPE=Release
-make
-```
-
-
-
-
-Windows Build
-
-**Note:** Windows is NOT suitable for real-time use but useful for tools and testing.
-
-Requirements:
-- Conan for Windows (tested with 2.9.1)
-- gcc for Windows (tested with w64devkit 2.0.0)
-- npcap (driver 1.80 + SDK 1.70)
-
-Follow the manual setup instructions above, using appropriate Windows paths.
-
-
-
-
-PikeOS Build
-
-Tested on PikeOS 5.1 for native personality (p4ext).
-
-Provide a CMake cross-toolchain file that defines the `PIKEOS` variable. Example process/thread configurations are in `examples/PikeOS/p4ext_config.c`.
-
-
-
----
-
-## Getting Started: Complete Walkthrough
-
-This section provides a complete end-to-end example using the **Freedom K64F board** with LAN9252 EtherCAT slave controller.
-
-### Hardware Requirements
-
-- **NXP Freedom K64F** development board
-- **LAN9252** EtherCAT slave controller (SPI connection)
-- **Ethernet cable** (connects slave to your PC)
-- **USB cable** (for programming the board)
-- **Linux PC** with EtherCAT master
-
-See the [NuttX Prerequisite section](#nuttx-prerequisite) before starting.
-
-### Step 1: Build the Slave Firmware
-
-```bash
-# Build firmware for Freedom K64F
-./scripts/build_slave_bin.sh freedom-k64f ~/nuttxspace/nuttx
-
-# Output will be in: build_freedom-k64f/easycat_frdm_k64f.bin
-# We have deployment scripts that are available here is an example:
-./examples/slave/nuttx/lan9252/freedom-k64f/deploy.sh build_freedom-k64f/easycat_frdm_k64f.bin
-```
-
-### Step 2: Flash the Firmware
-
-```bash
-# Deploy to the board (connects via USB)
-./examples/slave/nuttx/lan9252/freedom-k64f/board/deploy.sh \
- build_freedom-k64f/easycat_frdm_k64f.bin
-```
-
-### Step 3: Program the EEPROM
-
-The EtherCAT slave requires EEPROM configuration with device information:
-
-```bash
-# Connect slave to your PC via Ethernet
-# Write EEPROM (interface ? will be auto-detected)
-sudo ./tools/eeprom -s 0 -c write -f examples/slave/nuttx/lan9252/freedom-k64f/eeprom.bin -i "?"
-```
+KickCAT is a thin EtherCAT stack designed to be embedded in larger software with
+efficiency in mind. It provides **both master and slave** implementations in one
+codebase and runs on Linux (including RT-PREEMPT), Windows, PikeOS, and NuttX.
-**Note:** The `?` tells the tool to auto-detect the interface where the slave is connected.
-
-### Step 4: Run the Master
-
-Now you can control your slave using either C++ or Python:
-
-**Option A - C++ Master:**
-```bash
-# Run master example and follow terminal instructions
-sudo ./build/examples/master/freedom-k64f/freedom_k64f_example -i "?"
-```
-
-**Option B - Python Master:**
-```bash
-# Install KickCAT Python bindings
-pip install kickcat
-
-# Grant raw access to Python interpreter
-./py_bindings/enable_raw_access.sh
-
-# Run Python example
-python py_bindings/examples/freedom-k64f.py -i enp8s0
-```
-
-### Expected Output
-
-
-
-The master will:
-1. Discover the slave on the network
-2. Transition through states: INIT → PRE-OP → SAFE-OP → OP
-3. Begin exchanging process data (PDOs)
-4. Display diagnostic information
-
-
-Troubleshooting
-
-**Slave not detected:**
-- Check Ethernet cable connection
-- Verify EEPROM was written successfully
-- Check that slave firmware is running (LED indicators)
-
-**Permission denied:**
-- Ensure you're running master with `sudo` or proper capabilities
-- For Python: run `./py_bindings/enable_raw_access.sh`
-
-**Interface not found:**
-- List available interfaces: `ip link show`
-- Use the correct interface name (e.g., `eth0`, `enp8s0`, `eno1`)
-
-
-
----
-
-## Getting Started with Examples
-
-KickCAT includes working master and slave examples that work together out of the box.
-
-### Master Examples
-
-Located in `examples/master/`:
-
-- **easycat**: Basic example for EasyCAT shield
-- **elmo**: Motor control example (Elmo drives)
-- **ingenia**: Motor control example (Ingenia drives)
-- **freedom-k64f**: Example for Kinetis Freedom board
-- **gateway**: EtherCAT mailbox gateway implementation
-- **load_esi**: ESI file loading utility
-
-#### Running a Master Example
-
-**C++ Examples:**
-```bash
-cd build
-./examples/master/easycat/easycat_example -i eth0
-```
-
-**Python Examples:**
-
-KickCAT is available on PyPI for easy installation:
-
-```bash
-# Install from PyPI
-pip install kickcat
-
-# Run Python examples
-python py_bindings/examples/freedom-k64f.py --interface eth0
-
-# With redundancy
-python py_bindings/examples/easycat.py -i eth0 -r eth1
-```
-
-
-Python Examples Help
-
-```bash
-$ python py_bindings/examples/freedom-k64f.py --help
-usage: freedom-k64f.py [-h] -i INTERFACE [-r REDUNDANCY]
-
-EtherCAT master for Freedom K64F using EasyCAT
-
-options:
- -h, --help show this help message and exit
- -i INTERFACE, --interface INTERFACE
- Primary network interface (e.g., eth0)
- -r REDUNDANCY, --redundancy REDUNDANCY
- Redundancy network interface (e.g., eth1)
-```
-
-**Important:** Python interpreter needs raw socket capabilities:
-```bash
-# Use the helper script to grant permissions
-./py_bindings/enable_raw_access.sh
-```
-
-
-
-Replace `eth0` with your network interface name.
-
-### Slave Examples
-
-Located in `examples/slave/nuttx/`:
-
-**Supported Boards:**
-- **XMC4800** (Infineon XMC4800 Relax Kit)
-- **Arduino Due** (with EasyCAT shield + LAN9252)
-- **Freedom K64F** (NXP Kinetis with LAN9252)
-
-#### NuttX Prerequisite:
-
-NuttX Setup Instructions
-
-1. Install NuttX dependencies: https://nuttx.apache.org/docs/latest/quickstart/install.html
-2. Download ARM GCC toolchain (>= 12.0): https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads
-
-#### Board-Specific Setup
-
-**Arduino Due:**
-- Requires `bossac-1.6.1-arduino` for flashing (available from Arduino IDE installation)
-- Connect USB to the port closest to power jack
-- If flashing fails with "No device found on ttyACM0":
- - Press ERASE button for a few seconds, release
- - Press RESET button
- - Try flashing again
-
-**Freedom K64F:**
-- Standard OpenOCD flashing supported
-
-**XMC4800:**
-- Use provided flashing scripts in board directory
-
-
-
-
-#### Building Slave Examples
-
-All slave examples use NuttX RTOS. Use the automated build script:
-
-```bash
-./scripts/build_slave_bin.sh [build-name]
-```
-
-**Example:**
-```bash
-# Build for XMC4800
-./scripts/build_slave_bin.sh xmc4800-relax ~/nuttxspace/nuttx
+CoE (CANopen over EtherCAT) is fully supported on both sides. Beyond the stack
+itself, KickCAT ships a complete **software ESC and network emulator**, GUIs, and
+CLI tooling, so a bus can be developed, configured, and tested without physical
+hardware.
-# Deploy for XMC4800
-./examples/slave/nuttx/xmc4800/deploy.sh build_xmc4800-relax/xmc4800_relax.bin
+For exactly what is and isn't supported, see the
+[feature support matrix](docs/FEATURES.md).
-# Build for Arduino Due
-./scripts/build_slave_bin.sh arduino-due ~/nuttxspace/nuttx
+## Capabilities
-# Deploy for Arduino Due
-./examples/slave/nuttx/lan9252/arduino-due/deploy.sh build_arduino-due/easycat_arduino_due.bin
+### Master stack
-# Build for Freedom K64F
-./scripts/build_slave_bin.sh freedom-k64f ~/nuttxspace/nuttx
-
-# Deploy for Freedom K64F
-/examples/slave/nuttx/lan9252/freedom-k64f/deploy.sh build_freedom-k64f/easycat_frdm_k64f.bin
-```
-
-
-Testing Master-Slave Communication
-
-1. **Start the simulator or flash a slave:**
- ```bash
- # Option A: Use simulator with TAP socket (preferred, same machine)
- ./build/simulation/network_simulator -i "?" -s simulation/slave_configs/freedom-k64f.json
- # Then select "tap:server"
-
- # Option B: Flash real hardware (e.g., Arduino Due)
- ./scripts/build_slave_bin.sh arduino-due ~/nuttxspace/nuttx
- # Flash the resulting binary to your board
- ```
-
-2. **Run a master example:**
- ```bash
- # With TAP socket (select "tap:client"):
- sudo ./build/examples/master/easycat/easycat_example -i "?"
-
- # Or with the interface connected to your slave:
- sudo ./build/examples/master/easycat/easycat_example -i eth0
- ```
-
-3. **Expected behavior:**
- - Master transitions slave through states: INIT → PRE-OP → SAFE-OP → OP
- - PDO data exchange begins in OP state
- - Check console output for diagnostics
-
-
-
----
-
-## Multi-Slave Example
-
-This example demonstrates how to run **multiple EtherCAT slaves** (Freedom and XMC4800) on the same bus and read their data using the EasyCAT Python master.
-
-### 1. Build and deploy the slave firmware
-
-Follow the [Building Slave Examples section](#building-slave-examples) section to build and flash the firmware on both boards:
-- **Freedom board**
-- **XMC4800 board**
-
-Make sure both slaves are running before continuing.
-
-### 2. Connect the hardware
-
-Wire the boards according to the setup below:
-
-
-
-Ensure that:
-- All slaves are connected in the correct EtherCAT order
-- The master interface is connected to the first slave
-
-### 3. Run the Python EasyCAT master
-
-Start the EasyCAT Python master to read and display data from each detected slave:
-
-```bash
-python ./py_bindings/examples/easycat.py -i eth0
-```
-Replace eth0 with the network interface connected to your EtherCAT bus if needed
-
-### 3. Expected output
-The master will enumerate all slaves on the bus and continuously print their input/output data.
-
-Expected output:
-
----
-
-## Simulator
-
-Test your EtherCAT applications without physical hardware using the built-in network simulator.
-See [`simulation/README.md`](simulation/README.md) for the full guide (architecture, config schema, named TAP segments).
-
-The quickest way to drive an emulated slave is the **in-process** example — master and slave in one process, no network setup:
-
-```bash
-./build/examples/master/simulated_bus/simulated_bus -f "Beckhoff EL1xxx.xml" -t EL1008
-```
-
-The two-process `network_simulator` (below) is closer to a real setup and lets an unmodified master example connect over a TAP socket.
-
-### Transport Options
-
-When the master and the simulator run on the **same machine**, prefer using **TAP sockets** (shared-memory IPC) instead of a virtual Ethernet pair. TAP sockets are faster and simpler to set up — no kernel `veth` configuration is needed.
-
-When using the `?` interactive selector for the network interface, two TAP entries are available:
-- `tap:server` — to be used by the simulator
-- `tap:client` — to be used by the master
-
-If you need to run the master and simulator on **different machines**, use real network interfaces or a virtual Ethernet pair:
-
-```bash
-# Create a virtual ethernet pair (Linux, same machine, alternative to TAP)
-sudo ./simulation/create_virtual_ethernet.sh create veth
-```
-
-### Running the Simulator
-
-```bash
-# Start the simulator (must be started before the master)
-# Using TAP socket (preferred, same machine):
-./build/simulation/network_simulator -i "?" -s simulation/slave_configs/freedom-k64f.json
-# Then select "tap:server"
-
-# Using a specific interface:
-./build/simulation/network_simulator -i eth1 -s simulation/slave_configs/freedom-k64f.json
-
-# Multiple slaves:
-./build/simulation/network_simulator -i "?" -s simulation/slave_configs/freedom-k64f.json simulation/slave_configs/xmc4800.json
-```
-
-Then start the master on the matching transport:
-```bash
-# Using TAP socket (select "tap:client"):
-sudo ./build/examples/master/easycat/easycat_example -i "?"
-
-# Or with a specific interface:
-sudo ./build/examples/master/easycat/easycat_example -i eth0
-```
-
-**Current Capabilities:**
-- Load EEPROM configurations
-- Emulate basic sync manager behavior
-- Emulate basic FMMU (Fieldbus Memory Management Unit) behavior
-- CoE mailbox with SDO support (via ESI XML)
-- DL status / network topology emulation
-
-**Limitations:**
-- No interrupt emulation
-- No redundancy support yet
-
----
-
-## Tools
-
-KickCAT includes several utility tools in the `tools/` directory:
-
-- **eeprom**: Read/write/dump EEPROM from ESC
-- **scan_topology**: Scan the bus and display the network topology as an ASCII tree
-- **check_network_stability**: Monitor packet loss and corruption over time (Linux only)
-- **od_generator**: Generate Object Dictionary code from ESI files
-- **EtherCAT GUI**: PySide6-based graphical interface for bus monitoring
-
-Build tools with the main project:
-```bash
-cd build
-make
-ls tools/ # Your built tools will be here
-```
-
-
-EtherCAT GUI Tool Usage
-
-The KickCAT EtherCAT GUI is a PySide6-based application for monitoring and controlling the EtherCAT bus.
-
-#### Requirements
-- Python 3
-- PySide6
-- `kickcat` package (installed via `pip install -e .` in project root)
-
-#### Usage
-Run the application as a module from the project root:
-```bash
-python -m tools.ethercat_gui -i enp8s0
-```
-
-
-### EEPROM Tool Usage
-
-Read, write, or dump EEPROM content from your EtherCAT Slave Controller:
-
-```bash
-# Write EEPROM to slave at position 0
-sudo ./tools/eeprom -s 0 -c write -f path/to/eeprom.bin -i
-
-# Auto-detect interface
-sudo ./tools/eeprom -s 0 -c write -f path/to/eeprom.bin -i "?"
-
-# Read EEPROM from slave
-sudo ./tools/eeprom -s 0 -c read -f output.bin -i
-```
-
-### Object Dictionary Generator
-
-If your application uses CoE mailbox with SDO, you can generate Object Dictionary code from ESI files.
-
-#### Generate OD from ESI File
-
-```bash
-# Generate od_populator.cc from your ESI file
-./tools/od_generator -f your_device.esi
-
-# This creates: od_populator.cc
-```
-
-#### Using Generated OD Code
-
-Include the generated file in your slave application:
-
-```cpp
-#include "od_populator.h"
-
-int main() {
- // Initialize your slave
- // ...
-
- // Populate Object Dictionary
- auto dictionary = CoE::createOD();
-
- // Continue with slave operation
- // ...
-}
-```
-
-#### Custom OD Population
-
-You can also manually create `od_populator.cc` by implementing the `CoE::createOD()` function.
-
-**Examples:** See `examples/slave/nuttx/xmc4800/od_populator.cc` and `examples/slave/nuttx/lan9252/freedom-k64f/od_populator.cc` for reference implementations.
-
----
-
-## Architecture
-
-### Master Stack Status
-
-✅ **Implemented:**
-- Full EtherCAT state machine (INIT, PRE-OP, SAFE-OP, OP)
-- Process data (PI) read/write
-- CoE: SDO read/write (blocking and async)
-- CoE: Emergency messages
-- CoE: SDO Information service
+- Full EtherCAT State Machine (INIT, PRE-OP, SAFE-OP, OP)
+- Process data (PDO) read/write
+- CoE: SDO read/write (expedited, normal, segmented), SDO Information, Emergency
- Bus diagnostics with error counters
- Cable redundancy
-- Hook system for non-compliant slaves
- Consecutive writes (up to 255 datagrams in flight)
-- EtherCAT mailbox gateway (ETG.8200)
-- Distributed Clock (DC) support - experimental
-- AF_XDP Linux socket for improved performance *(available, opt-in)*
-
-📋 **Planned:**
-- CoE: Segmented transfer (partial)
-- CoE: Diagnosis message (0x10F3)
-- FoE, EoE, AoE, SoE profiles
-- Auto-discovery of broken wires
-- Addressing groups (multi-PDO)
+- Mailbox gateway (ETG.8200)
+- Distributed Clock (experimental)
+- AF_XDP socket backend on Linux (opt-in, lower latency)
+- Python bindings
-### Slave Stack Status
+### Slave stack
-✅ **Implemented:**
-- State machine: INIT → PRE-OP → SAFE-OP → OP
+- Full EtherCAT State Machine
- Process data read/write
+- CoE: Object Dictionary, SDO (including segmented and SDO Information)
- ESC support: LAN9252 (SPI), XMC4800
-- CoE: Object dictionary
-- CoE: SDO support
-- EEPROM flash/dump tools
-- CTT (Conformance Test Tool) validated (WDC_FOOT)
+- EEPROM provisioning tooling
+- Conformance Test Tool (CTT) validated (WDC_FOOT)
-📋 **Planned:**
-- Extended mailbox protocols (SDO Information, FoE, EoE)
-- Multi-PDO support (>2 sync managers)
-- Distributed clock
-- Enhanced error reporting via AL_STATUS
+### Mailbox protocols
----
+CoE is fully supported on master and slave. FoE and EoE are planned. SoE, AoE,
+and VoE are not currently on the roadmap (no maintainer hardware to test
+against) -- contributions are welcome. See the
+[feature support matrix](docs/FEATURES.md) for the full breakdown.
-## Performance Optimization (Linux)
-
-For real-time performance on Linux:
-
-1. **Use RT-PREEMPT kernel**
- ```bash
- # Check if RT patches are applied
- uname -a | grep PREEMPT
- ```
-
-2. **Set real-time scheduler**
- ```bash
- sudo chrt -f 80 ./your_ethercat_app
- ```
-
-3. **Disable NIC interrupt coalescing**
- ```bash
- sudo ethtool -C eth0 rx-usecs 0 tx-usecs 0
- ```
-
-4. **Disable RT throttling**
- ```bash
- echo -1 | sudo tee /proc/sys/kernel/sched_rt_runtime_us
- ```
-
-5. **Isolate CPU cores**
- ```bash
- # Add to kernel boot parameters
- isolcpus=2,3 nohz_full=2,3 rcu_nocbs=2,3
- ```
-
-6. **Adjust network IRQ priority**
- ```bash
- # Find IRQ number
- cat /proc/interrupts | grep eth0
- # Set priority
- sudo chrt -f 90 -p
- ```
-
-7. **Use AF_XDP socket (optional, Linux only)**
-
- AF_XDP bypasses most of the kernel networking stack by using shared memory
- ring buffers between user space and the NIC driver. This can reduce latency
- significantly compared to the default `AF_PACKET` raw socket.
-
- **Build requirements:** `libxdp-dev`, `libbpf-dev`, `clang` (for BPF compilation).
-
- ```bash
- # Install dependencies (Debian/Ubuntu)
- sudo apt install libxdp-dev libbpf-dev clang
-
- # Build with AF_XDP support
- cmake .. -DENABLE_AF_XDP=ON
- make
- ```
-
- **Usage:** prefix your interface name with `xdp:` to select the AF_XDP backend:
-
- ```bash
- # AF_XDP socket (requires CAP_NET_ADMIN + CAP_BPF, or root)
- sudo ./examples/master/easycat/easycat_example -i xdp:eth0
-
- # Regular AF_PACKET socket (default, unchanged)
- sudo ./examples/master/easycat/easycat_example -i eth0
- ```
-
- **Requirements:**
- - Linux kernel >= 5.4 with `CONFIG_XDP_SOCKETS=y` (see check below)
- - `CAP_NET_ADMIN` + `CAP_BPF` capabilities (or root)
- - NIC driver with XDP support (most modern drivers: `i40e`, `ixgbe`, `mlx5`, `igc`, `e1000e`, etc.)
-
- **Verify kernel support:**
- ```bash
- grep CONFIG_XDP_SOCKETS /boot/config-$(uname -r)
- # Expected: CONFIG_XDP_SOCKETS=y
- ```
-
- If `CONFIG_XDP_SOCKETS` is not set or missing, add the following to your kernel
- configuration and rebuild:
- ```
- CONFIG_BPF_SYSCALL=y
- CONFIG_XDP_SOCKETS=y
- CONFIG_XDP_SOCKETS_DIAG=y
- ```
+### Tooling and GUIs
----
+- **KickUI** -- ImGui bus dashboard: topology view, SDO/PDO panels, DS402 motor bench
+- **EEPROM editor** -- ImGui structured SII/EEPROM editor
+- **eeprom** -- CLI to read/write slave EEPROM
+- **scan_topology** -- enumerate slaves and per-port link status
+- **check_network_stability** -- monitor packet loss/corruption over time (Linux)
+- **od_generator** -- generate CoE Object Dictionary code from ESI files
+- **ethercat_gui** -- PySide6 bus monitoring application
-### EtherCAT Specifications
-- [ETG Official Documentation](https://www.ethercat.org/en/downloads.html)
-- [Beckhoff EtherCAT Documentation](https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_io_intro/1257993099.html)
-- [ESC Datasheets](https://download.beckhoff.com/download/document/io/ethercat-development-products/)
+See [docs/TOOLS.md](docs/TOOLS.md) for usage.
-### Learning Resources
-- [EtherCAT Device Protocol Poster](https://www.ethercat.org/download/documents/EtherCAT_Device_Protocol_Poster.pdf)
-- [EtherCAT Diagnostics Guide](https://www.automation.com/en-us/articles/2014-2/diagnostics-with-ethercat-part-4)
-- [ESC Comparison](https://download.beckhoff.com/download/document/io/ethercat-development-products/an_esc_comparison_v2i7.pdf)
+### Simulation and emulation
----
+KickCAT includes a software EtherCAT Slave Controller (`EmulatedESC`: registers,
+SyncManagers, FMMUs, DC clock, EEPROM) and a network fabric (`EmulatedNetwork`:
+topology routing, redundancy, runtime wire break/heal). Run a master against it
+either in-process (the `simulated_bus` example) or as a separate process
+(`network_simulator` over a shared-memory TAP socket).
-## Testing
+See [docs/SIMULATION.md](docs/SIMULATION.md).
-### Unit Tests
+## Getting started
+
+Build the stack and tools (Linux):
```bash
-# Enable unit tests and set up
./scripts/configure.sh build --with=unit_tests
./scripts/setup_build.sh build
-
-# Build and run tests
-cd build && make
-make test
+cd build && make -j
```
-### Code Coverage
+Then run a master against an emulated slave -- no hardware, single process:
-Install gcovr and build with coverage:
```bash
-# Install gcovr
-uv pip install gcovr
-
-# Enable tests + coverage
-./scripts/configure.sh build --with=unit_tests --with=code_coverage
-./scripts/setup_build.sh build
-
-# Build and generate coverage
-cd build && make
-make coverage
+./build/examples/master/simulated_bus/simulated_bus \
+ -f examples/slave/nuttx/lan9252/freedom-k64f/freedom-k64f.xml -t Board
```
----
-
-## Release Process
-
-KickCAT follows [Semantic Versioning](https://semver.org/).
+Point `-f` at any vendor ESI XML and `-t` at the device `` to emulate a
+different slave. Beckhoff publish ESI files for their devices at
+.
-### Release Requirements
+Where to go next:
-Before a version leaves release candidate status:
-- ✅ 5+ continuous days of testing without bugs (no realtime loss, crashes, or memory leaks)
-- ✅ 80% line coverage and 50% branch coverage for master/slave stack
+- Build, install, Python bindings, Windows/PikeOS -- [docs/BUILDING.md](docs/BUILDING.md)
+- Real hardware: slave firmware, flashing, end-to-end walkthrough -- [docs/HARDWARE.md](docs/HARDWARE.md)
+- Simulator and emulator -- [docs/SIMULATION.md](docs/SIMULATION.md)
+- Tools and GUIs -- [docs/TOOLS.md](docs/TOOLS.md)
+- Real-time performance tuning -- [docs/PERFORMANCE.md](docs/PERFORMANCE.md)
-Note: integration test is done with the master running on Linux (x86-64) and the slave is the Freedom-K64F
-
----
-
-## Contributing
+## Platform support
-Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
+The master runs as a host OS process; the slave runs the stack on an RTOS
+against an EtherCAT Slave Controller (ESC).
-### Development Setup
+**Master (host OS):**
-```bash
-# Clone repository
-git clone https://github.com/leducp/KickCAT.git
-cd KickCAT
+| OS | Architecture | Status |
+|------------|--------------|----------------------------------------------|
+| Linux | x86-64 | Production; RT-PREEMPT recommended for real-time |
+| PikeOS 5.1 | ARMv8 | Production |
+| Windows | x86-64 | Tools and testing only (not real-time) |
-# Configure and setup build environment
-./scripts/configure.sh build --with=unit_tests
-./scripts/setup_build.sh build
+**Slave (NuttX RTOS + ESC):**
-# Build
-cd build && make
-```
+| ESC | Interface | Status |
+|----------|------------|--------------------------|
+| LAN9252 | SPI | Production |
+| XMC4800 | Integrated | Production; CTT validated |
----
+Reference boards: NXP Freedom K64F (LAN9252), Arduino Due with EasyCAT shield
+(LAN9252), Infineon XMC4800 Relax Kit (XMC4800). See the
+[hardware guide](docs/HARDWARE.md).
-## Platform Support
+## Documentation
-| Platform | Type | Status |
-|----------|--------|-------|
-| Linux (x86_64) | Master | Production - RT_PREEMPT Recommended for real-time |
-| Windows | Master | ⚠️ Testing/tools only |
-| PikeOS 5.1 (ARMv8) | Master | Production |
-| NuttX RTOS | Slave | Production |
-| Arduino Due | Slave | via NuttX |
-| Infineon XMC4800 | Slave | via NuttX, CTT validated |
-| NXP Freedom K64F | Slave | via NuttX |
+- [Feature support matrix](docs/FEATURES.md)
+- [Building and installing](docs/BUILDING.md)
+- [Hardware guide](docs/HARDWARE.md)
+- [Simulation and emulation](docs/SIMULATION.md)
+- [Tools and GUIs](docs/TOOLS.md)
+- [Real-time performance tuning](docs/PERFORMANCE.md)
+- [Architecture overview](docs/architecture.md)
+- [Release procedure](release/RELEASE_PROCEDURE.md)
----
+### EtherCAT references
-## Known Limitations
+- [ETG official documentation](https://www.ethercat.org/en/downloads.html)
+- [Beckhoff EtherCAT documentation](https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_io_intro/1257993099.html)
+- [Beckhoff ESI (XML device description) files](https://download.beckhoff.com/download/configuration-files/io/ethercat/xml-device-description)
+- [ESC datasheets](https://download.beckhoff.com/download/document/io/ethercat-development-products/)
+- [EtherCAT Device Protocol Poster](https://www.ethercat.org/download/documents/EtherCAT_Device_Protocol_Poster.pdf)
+- [ESC comparison](https://download.beckhoff.com/download/document/io/ethercat-development-products/an_esc_comparison_v2i7.pdf)
-### Master Stack
-- **Little-endian only**: Current implementation supports little-endian hosts only
-- **Windows**: Not suitable for real-time applications
-- **Mailbox protocols**: Limited to CoE SDO (FoE, EoE planned)
+## Contributing
-### Slave Stack
-- **PDO limitation**: Currently supports up to 2 sync managers (working on multi-PDO)
-- **Distributed Clock**: Not yet implemented
-- **Mailbox protocols**: Limited to CoE SDO (FoE, EoE planned)
+Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for code-style
+and PR conventions, and [docs/BUILDING.md](docs/BUILDING.md) for the development
+build (unit tests and coverage).
----
+KickCAT follows [Semantic Versioning](https://semver.org/). The release workflow
+is documented in [release/RELEASE_PROCEDURE.md](release/RELEASE_PROCEDURE.md).
## License
[CeCILL-C](LICENSE)
----
-
-## Support & Community
-
-- **Issues**: [GitHub Issues](https://github.com/leducp/KickCAT/issues)
-- **Discussions**: [GitHub Discussions](https://github.com/leducp/KickCAT/discussions)
-- **Conan Package**: [conan-center-index](https://github.com/conan-io/conan-center-index/tree/master/recipes/kickcat)
-
----
-
-## Project Status
-
-🟢 **Active Development** - KickCAT is actively maintained and used in production systems.
+## Support
-**Current Version**: Check [Releases](https://github.com/leducp/KickCAT/releases) for the latest stable version.
+- Issues: [GitHub Issues](https://github.com/leducp/KickCAT/issues)
+- Discussions: [GitHub Discussions](https://github.com/leducp/KickCAT/discussions)
+- Conan package: [conan-center-index](https://github.com/conan-io/conan-center-index/tree/master/recipes/kickcat)
-**Release Cycle**: Following semantic versioning with thorough testing before each major release.
+Status: actively maintained and used in production systems. See
+[Releases](https://github.com/leducp/KickCAT/releases) for the latest stable
+version.
diff --git a/docs/BUILDING.md b/docs/BUILDING.md
new file mode 100644
index 00000000..fb429c0a
--- /dev/null
+++ b/docs/BUILDING.md
@@ -0,0 +1,168 @@
+# Building KickCAT
+
+KickCAT uses Conan (for dependencies) and CMake, wrapped by the scripts in
+`scripts/`. Prefer the wrappers over invoking `cmake` / `conan` directly.
+
+## Prerequisites
+
+- **Linux**: gcc, cmake, conan
+- **Python bindings**: uv or pip
+- **Hardware access**: a network interface with raw-socket capability
+
+## Linux (recommended)
+
+```bash
+# 1. Configure build options (optional -- defaults are sensible)
+./scripts/configure.sh build --with=unit_tests
+
+# 2. Set up the build environment (installs Conan deps + runs CMake)
+./scripts/setup_build.sh build
+
+# 3. Build
+cd build && make -j
+
+# 4. Grant network capabilities (required for raw-socket access)
+sudo setcap 'cap_net_raw,cap_net_admin=+ep' ./tools/your_binary
+```
+
+`configure.sh` stores the selected options in `.buildconfig`, which
+`setup_build.sh` consumes. Available options include `unit_tests`,
+`code_coverage`, `esi_parser`, `simulation`, `tools`, `master_examples`,
+`slave_examples`, `eeprom_editor`, and `kickui`.
+
+### Rebuild after source changes
+
+From an existing `build` directory, no need to re-run `configure.sh` /
+`setup_build.sh` unless CMakeLists or Conan deps changed:
+
+```bash
+cd build && make -j
+```
+
+### GUI tools (KickUI, EEPROM editor)
+
+These are off by default and need ImGui + GLFW:
+
+```bash
+./scripts/configure.sh build --with=kickui --with=eeprom_editor
+./scripts/setup_build.sh build
+cd build && make -j
+```
+
+See [TOOLS.md](TOOLS.md) for what each tool does.
+
+## Python bindings
+
+```bash
+# Install with uv (recommended)
+uv pip install .
+
+# Or for development (faster rebuilds)
+uv pip install --no-build-isolation -Cbuild-dir=/tmp/build -v .
+```
+
+The wheel build enables the EEPROM-editor GUI (`BUILD_EEPROM_EDITOR=ON` in
+`pyproject.toml`), which needs `imgui` and `glfw`. The cibuildwheel images
+provide them; on a bare environment that lacks them, either install them (via
+Conan) or disable the GUI for the build:
+
+```bash
+uv pip install --config-setting=cmake.define.BUILD_EEPROM_EDITOR=OFF .
+```
+
+The published package is available on PyPI:
+
+```bash
+pip install kickcat
+```
+
+The Python interpreter needs raw-socket capabilities to drive a bus:
+
+```bash
+./py_bindings/enable_raw_access.sh
+```
+
+### Multi-wheel (CI)
+
+This project uses cibuildwheel to generate wheels for all supported
+configurations. To run it locally:
+
+```bash
+uvx cibuildwheel
+```
+
+## Manual build (without the wrapper scripts)
+
+```bash
+# 1. Create the build directory
+mkdir -p build
+
+# 2. Install dependencies with Conan
+python3 -m venv kickcat_venv
+source kickcat_venv/bin/activate
+pip install conan
+
+conan install conan/conanfile.py -of=build/ \
+ -pr:h conan/your_profile_host.txt \
+ -pr:b conan/your_profile_target.txt \
+ --build=missing -s build_type=Release
+
+# Or create the Conan package directly
+conan create conan/all --build=missing --version 2.5 -pr build/profile.txt
+
+# 3. Configure and build
+cd build
+cmake .. -DCMAKE_BUILD_TYPE=Release
+make -j
+```
+
+## Windows
+
+Windows is **not** suitable for real-time use, but it is useful for tools and
+testing.
+
+Requirements:
+
+- Conan for Windows (tested with 2.9.1)
+- gcc for Windows (tested with w64devkit 2.0.0)
+- npcap (driver 1.80 + SDK 1.70)
+
+Follow the manual build instructions above, using the appropriate Windows paths
+and the `conan/profile_windows_x86_64.txt` profile.
+
+## PikeOS
+
+Tested on PikeOS 5.1 for the native personality (p4ext).
+
+Provide a CMake cross-toolchain file that defines the `PIKEOS` variable. Example
+process/thread configurations are in `lib/src/OS/PikeOS/p4ext_config.c`.
+
+## Slave firmware
+
+Building and flashing NuttX slave firmware (XMC4800, Arduino Due, Freedom K64F)
+is covered in [HARDWARE.md](HARDWARE.md).
+
+## Testing
+
+### Unit tests
+
+```bash
+./scripts/configure.sh build --with=unit_tests
+./scripts/setup_build.sh build
+cd build && make -j
+make test
+```
+
+The test binary is `build/kickcat_unit`. Run a subset with
+`./kickcat_unit --gtest_filter='*'`.
+
+### Code coverage
+
+```bash
+uv pip install gcovr
+
+./scripts/configure.sh build --with=unit_tests --with=code_coverage
+./scripts/setup_build.sh build
+cd build && make -j
+make coverage
+```
diff --git a/docs/FEATURES.md b/docs/FEATURES.md
new file mode 100644
index 00000000..f56a4d98
--- /dev/null
+++ b/docs/FEATURES.md
@@ -0,0 +1,120 @@
+# Feature support matrix
+
+This document maps the EtherCAT feature set to what the KickCAT stack currently
+provides, separately for the **master** and **slave** sides. It is the
+authoritative source for "what works today"; the README only summarizes it.
+
+## Legend
+
+| Status | Meaning |
+|----------------|--------------------------------------------------------------------------------|
+| Supported | Implemented and exercised by examples and/or unit tests. |
+| Partial | Usable but incomplete, or limited to a subset of the feature. |
+| Experimental | Implemented but not yet validated for production use. |
+| Planned | On the roadmap; protocol definitions or scaffolding may already exist. |
+| Not planned | No maintainer hardware to develop or test against. Contributions are welcome. |
+| Not applicable | The feature does not apply to that side. |
+
+## State machine and process data
+
+| Feature | Master | Slave |
+|------------------------------------------|-----------|-----------|
+| EtherCAT State Machine (INIT/PRE-OP/SAFE-OP/OP) | Supported | Supported |
+| Process data exchange (PDO read/write) | Supported | Supported |
+| FMMU configuration | Supported | Supported |
+| SyncManager configuration | Supported | Supported |
+| One input + one output PDO mapping per slave | Supported | Supported |
+| Multiple PDO SyncManagers (>1 input or >1 output per slave) | Not supported | Not supported |
+| Mailbox status polling via dedicated FMMUs (LRD/LRW) | Supported | Not applicable |
+
+## Mailbox protocols
+
+| Protocol | Master | Slave | Notes |
+|----------|------------|------------|-------|
+| CoE (CANopen over EtherCAT) | Supported | Supported | See CoE breakdown below. |
+| FoE (File over EtherCAT) | Planned | Planned | Protocol header only; no mailbox handlers yet. |
+| EoE (Ethernet over EtherCAT)| Planned | Planned | Protocol header only; no mailbox handlers yet. |
+| SoE (Servo over EtherCAT) | Not planned | Not planned | ESI parsing only. No maintainer hardware; contributions welcome. |
+| AoE (ADS over EtherCAT) | Not planned | Not planned | ESI parsing only. No maintainer hardware; contributions welcome. |
+| VoE (Vendor over EtherCAT) | Not planned | Not planned | ESI parsing only. No maintainer hardware; contributions welcome. |
+
+### CoE breakdown
+
+| CoE feature | Master | Slave |
+|-------------------------------------|-----------|-----------|
+| SDO expedited upload/download | Supported | Supported |
+| SDO normal (sized) transfer | Supported | Supported |
+| SDO segmented transfer | Supported | Supported |
+| SDO Information service | Supported | Supported |
+| Emergency messages | Supported | Not applicable |
+| Object Dictionary | Not applicable | Supported |
+| PDO mapping / assignment | Supported | Supported |
+
+## Distributed Clocks (DC)
+
+| Feature | Master | Slave |
+|---------------------------------|--------------|-------------|
+| DC synchronization | Experimental | Planned |
+| DC modeling in the emulator | Supported (local clock, drift-ppm injection, SYNC0) | -- |
+
+The ESC emulator models a DC clock with configurable drift; see
+[SIMULATION.md](SIMULATION.md). Slave-side DC is not implemented on real ESCs yet.
+
+## Networking and reliability
+
+| Feature | Master | Slave |
+|-------------------------------------------|-----------|-----------|
+| Cable redundancy | Supported | Not applicable |
+| Consecutive writes (frames in flight) | Supported | Not applicable |
+| Mailbox gateway (ETG.8200) | Supported | Not applicable |
+| Bus diagnostics and error counters | Supported | Supported |
+| AF_XDP socket backend (Linux, opt-in) | Supported | Not applicable |
+| Auto-discovery of broken wires | Planned | Not applicable |
+
+## EEPROM / SII
+
+| Feature | Master | Slave |
+|----------------------------------|-----------|-----------|
+| SII (EEPROM) parsing | Supported | Supported |
+| EEPROM read/dump tooling | Supported | Not applicable |
+| EEPROM write (slave provisioning)| Supported | Not applicable |
+
+See [TOOLS.md](TOOLS.md) for the `eeprom` CLI and the EEPROM editor GUI.
+
+## Platforms
+
+The master and slave run on different layers: the master is a host OS process,
+while the slave is the stack running on an RTOS against an EtherCAT Slave
+Controller (ESC).
+
+### Master (host operating system)
+
+| OS | Architecture | Status |
+|------------|--------------|----------------------------------------------|
+| Linux | x86-64 | Supported; RT-PREEMPT recommended for real-time |
+| PikeOS 5.1 | ARMv8 | Supported |
+| Windows | x86-64 | Tools and testing only (not real-time) |
+
+### Slave (RTOS + ESC hardware)
+
+The slave stack runs on the NuttX RTOS. Supported EtherCAT Slave Controllers:
+
+| ESC | Interface | Status |
+|----------|------------|--------------------------|
+| LAN9252 | SPI | Supported |
+| XMC4800 | Integrated | Supported; CTT-validated |
+
+Reference boards: NXP Freedom K64F (LAN9252), Arduino Due with EasyCAT shield
+(LAN9252), and the Infineon XMC4800 Relax Kit (XMC4800). Build and flashing
+details are in [HARDWARE.md](HARDWARE.md).
+
+## Known limitations
+
+- Little-endian hosts only.
+- Windows is not suitable for real-time operation; use it for tooling and tests.
+- Process data is limited to one input and one output PDO SyncManager per slave
+ on both master and slave; multiple PDO SyncManagers per direction are not
+ supported.
+- Slave-side Distributed Clocks are not implemented.
+- The simulator/emulator does not emulate interrupts; see
+ [SIMULATION.md](SIMULATION.md).
diff --git a/docs/HARDWARE.md b/docs/HARDWARE.md
new file mode 100644
index 00000000..17bad819
--- /dev/null
+++ b/docs/HARDWARE.md
@@ -0,0 +1,237 @@
+# Hardware guide: slaves, firmware, and deployment
+
+This guide covers running KickCAT against real hardware: building and flashing
+NuttX slave firmware, provisioning EEPROM, and running a master against the
+slaves. For a no-hardware path, use the simulator instead -- see
+[SIMULATION.md](SIMULATION.md).
+
+Build the host-side binaries first; see [BUILDING.md](BUILDING.md).
+
+---
+
+## Complete walkthrough: Freedom K64F + LAN9252
+
+End-to-end example using the **NXP Freedom K64F** board with a **LAN9252**
+EtherCAT slave controller.
+
+### Hardware requirements
+
+- NXP Freedom K64F development board
+- LAN9252 EtherCAT slave controller (SPI connection)
+- Ethernet cable (slave to PC)
+- USB cable (for programming the board)
+- Linux PC running the EtherCAT master
+
+See [NuttX prerequisites](#nuttx-prerequisites) before starting.
+
+### Step 1: Build the slave firmware
+
+```bash
+./scripts/build_slave_bin.sh freedom-k64f ~/nuttxspace/nuttx
+# Output: build_freedom-k64f/easycat_frdm_k64f.bin
+```
+
+### Step 2: Flash the firmware
+
+```bash
+./examples/slave/nuttx/lan9252/freedom-k64f/deploy.sh \
+ build_freedom-k64f/easycat_frdm_k64f.bin
+```
+
+### Step 3: Program the EEPROM
+
+The slave requires EEPROM configuration with device information:
+
+```bash
+# Connect the slave to your PC via Ethernet, then write the EEPROM.
+# "?" auto-detects the interface where the slave is connected.
+sudo ./tools/eeprom -s 0 -c write -f examples/slave/nuttx/lan9252/freedom-k64f/eeprom.bin -i "?"
+```
+
+### Step 4: Run the master
+
+C++ master:
+
+```bash
+sudo ./build/examples/master/freedom-k64f/freedom_k64f_static_map_example -i "?"
+```
+
+Python master:
+
+```bash
+pip install kickcat
+./py_bindings/enable_raw_access.sh
+python py_bindings/examples/freedom-k64f.py -i enp8s0
+```
+
+### Expected output
+
+
+
+The master will:
+
+1. Discover the slave on the network.
+2. Transition through INIT -> PRE-OP -> SAFE-OP -> OP.
+3. Begin exchanging process data (PDOs).
+4. Display diagnostic information.
+
+### Troubleshooting
+
+**Slave not detected**
+
+- Check the Ethernet cable connection.
+- Verify the EEPROM was written successfully.
+- Check that the slave firmware is running (LED indicators).
+
+**Permission denied**
+
+- Run the master with `sudo` or grant capabilities (see [BUILDING.md](BUILDING.md)).
+- For Python: run `./py_bindings/enable_raw_access.sh`.
+
+**Interface not found**
+
+- List interfaces: `ip link show`.
+- Use the correct interface name (e.g. `eth0`, `enp8s0`, `eno1`).
+
+---
+
+## Examples
+
+### Master examples
+
+Located in `examples/master/`:
+
+- **easycat**: basic example for the EasyCAT shield
+- **elmo**: motor control (Elmo drives)
+- **ingenia**: motor control (Ingenia drives)
+- **freedom-k64f**: example for the Kinetis Freedom board
+- **gateway**: EtherCAT mailbox gateway (ETG.8200)
+- **load_esi**: ESI file loading utility
+- **wdc_foot**: CTT conformance example
+- **simulated_bus**: in-process master + emulated slave (no hardware) -- see
+ [SIMULATION.md](SIMULATION.md)
+
+Run a C++ example:
+
+```bash
+cd build
+./examples/master/easycat/easycat_example -i eth0
+```
+
+Run a Python example:
+
+```bash
+pip install kickcat
+python py_bindings/examples/freedom-k64f.py --interface eth0
+
+# With redundancy
+python py_bindings/examples/easycat.py -i eth0 -r eth1
+```
+
+The Python interpreter needs raw-socket capabilities:
+
+```bash
+./py_bindings/enable_raw_access.sh
+```
+
+### Slave examples
+
+Located in `examples/slave/nuttx/`. Supported boards:
+
+- **XMC4800** (Infineon XMC4800 Relax Kit)
+- **Arduino Due** (with EasyCAT shield + LAN9252)
+- **Freedom K64F** (NXP Kinetis with LAN9252)
+
+---
+
+## NuttX prerequisites
+
+1. Install NuttX dependencies:
+
+2. Download the ARM GCC toolchain (>= 12.0):
+
+
+### Board-specific setup
+
+**Arduino Due**
+
+- Requires `bossac-1.6.1-arduino` for flashing (from the Arduino IDE install).
+- Connect USB to the port closest to the power jack.
+- If flashing fails with "No device found on ttyACM0": press ERASE for a few
+ seconds, release, press RESET, and try again.
+
+**Freedom K64F**
+
+- Standard OpenOCD flashing supported.
+
+**XMC4800**
+
+- Use the provided flashing scripts in the board directory (J-Link).
+
+---
+
+## Building and deploying slave firmware
+
+All slave examples use NuttX. Use the automated build script:
+
+```bash
+./scripts/build_slave_bin.sh [build-name]
+```
+
+Examples:
+
+```bash
+# XMC4800
+./scripts/build_slave_bin.sh xmc4800-relax ~/nuttxspace/nuttx
+./examples/slave/nuttx/xmc4800/deploy.sh build_xmc4800-relax/xmc4800_relax.bin
+
+# Arduino Due
+./scripts/build_slave_bin.sh arduino-due ~/nuttxspace/nuttx
+./examples/slave/nuttx/lan9252/arduino-due/deploy.sh build_arduino-due/easycat_arduino_due.bin
+
+# Freedom K64F
+./scripts/build_slave_bin.sh freedom-k64f ~/nuttxspace/nuttx
+./examples/slave/nuttx/lan9252/freedom-k64f/deploy.sh build_freedom-k64f/easycat_frdm_k64f.bin
+```
+
+CI artifacts can be extracted and deployed with:
+
+```bash
+./scripts/deploy_artifacts.sh
+```
+
+---
+
+## Multi-slave example
+
+Run **multiple slaves** (Freedom and XMC4800) on the same bus and read their
+data with the EasyCAT Python master.
+
+### 1. Build and deploy the firmware
+
+Follow the section above to build and flash both boards (Freedom and XMC4800).
+Make sure both slaves are running before continuing.
+
+### 2. Connect the hardware
+
+
+
+Ensure that:
+
+- All slaves are connected in the correct EtherCAT order.
+- The master interface is connected to the first slave.
+
+### 3. Run the Python EasyCAT master
+
+```bash
+python ./py_bindings/examples/easycat.py -i eth0
+```
+
+Replace `eth0` with the interface connected to your bus.
+
+### Expected output
+
+The master enumerates all slaves and continuously prints their input/output
+data.
+
+
diff --git a/docs/PERFORMANCE.md b/docs/PERFORMANCE.md
new file mode 100644
index 00000000..839e0423
--- /dev/null
+++ b/docs/PERFORMANCE.md
@@ -0,0 +1,94 @@
+# Real-time performance tuning (Linux)
+
+Guidance for low-latency, deterministic operation of a KickCAT master on Linux.
+
+## 1. Use an RT-PREEMPT kernel
+
+```bash
+uname -a | grep PREEMPT
+```
+
+## 2. Set a real-time scheduler
+
+```bash
+sudo chrt -f 80 ./your_ethercat_app
+```
+
+## 3. Disable NIC interrupt coalescing
+
+```bash
+sudo ethtool -C eth0 rx-usecs 0 tx-usecs 0
+```
+
+## 4. Disable RT throttling
+
+```bash
+echo -1 | sudo tee /proc/sys/kernel/sched_rt_runtime_us
+```
+
+## 5. Isolate CPU cores
+
+Add to the kernel boot parameters:
+
+```
+isolcpus=2,3 nohz_full=2,3 rcu_nocbs=2,3
+```
+
+## 6. Adjust network IRQ priority
+
+```bash
+# Find the IRQ number
+cat /proc/interrupts | grep eth0
+# Set the priority of the IRQ thread
+sudo chrt -f 90 -p
+```
+
+## 7. AF_XDP socket (optional)
+
+AF_XDP bypasses most of the kernel networking stack using shared-memory ring
+buffers between user space and the NIC driver. This can reduce latency
+significantly compared to the default `AF_PACKET` raw socket.
+
+**Build requirements:** `libxdp-dev`, `libbpf-dev`, `clang` (for BPF compilation).
+
+```bash
+# Install dependencies (Debian/Ubuntu)
+sudo apt install libxdp-dev libbpf-dev clang
+
+# Build with AF_XDP support
+cmake .. -DENABLE_AF_XDP=ON
+make -j
+```
+
+**Usage:** prefix the interface name with `xdp:` to select the AF_XDP backend:
+
+```bash
+# AF_XDP socket (requires CAP_NET_ADMIN + CAP_BPF, or root)
+sudo ./examples/master/easycat/easycat_example -i xdp:eth0
+
+# Regular AF_PACKET socket (default, unchanged)
+sudo ./examples/master/easycat/easycat_example -i eth0
+```
+
+**Requirements:**
+
+- Linux kernel >= 5.4 with `CONFIG_XDP_SOCKETS=y` (see the check below)
+- `CAP_NET_ADMIN` + `CAP_BPF` capabilities (or root)
+- A NIC driver with XDP support (most modern drivers: `i40e`, `ixgbe`, `mlx5`,
+ `igc`, `e1000e`, and others)
+
+**Verify kernel support:**
+
+```bash
+grep CONFIG_XDP_SOCKETS /boot/config-$(uname -r)
+# Expected: CONFIG_XDP_SOCKETS=y
+```
+
+If `CONFIG_XDP_SOCKETS` is not set, add the following to your kernel
+configuration and rebuild:
+
+```
+CONFIG_BPF_SYSCALL=y
+CONFIG_XDP_SOCKETS=y
+CONFIG_XDP_SOCKETS_DIAG=y
+```
diff --git a/docs/SIMULATION.md b/docs/SIMULATION.md
new file mode 100644
index 00000000..a5d9d608
--- /dev/null
+++ b/docs/SIMULATION.md
@@ -0,0 +1,152 @@
+# Simulation and emulation
+
+KickCAT ships with a software EtherCAT Slave Controller and a network fabric, so
+a master application can be developed and tested with no physical hardware.
+
+There are two layers:
+
+- The **emulator** is the engine: `EmulatedESC` is a software ESC (registers,
+ SyncManagers, FMMUs, EEPROM, DC clock) and `EmulatedNetwork` wires emulated
+ ESCs into a topology. Both live in `lib/slave/include/kickcat/`.
+- The **simulator** is how you run a master against the emulator: either
+ in-process (the `simulated_bus` example) or as a separate process
+ (`network_simulator`, under `simulation/`).
+
+---
+
+## Emulator engine
+
+### EmulatedESC
+
+`EmulatedESC` (`lib/slave/include/kickcat/ESC/EmulatedESC.h`) models a complete
+EtherCAT Slave Controller and is driven by the real slave stack
+(`Slave` + `PDO` + optional CoE mailbox). It implements:
+
+- 16 SyncManagers, including mailbox SyncManagers (RxSM/TxSM).
+- 16 FMMUs (logical-to-physical process-data mapping).
+- AL (Application Layer) state machine registers and event masks.
+- DL (Data Link) port descriptors, per-port link status, and error counters.
+- EEPROM loaded from a raw `.bin` or compiled from an ESI XML device.
+- A DC local clock with configurable drift (ppm), receive-time latching,
+ system-time offset, and SYNC0.
+- PDI and process-data watchdogs.
+- Per-port loopback behaviour (open/closed ports, circulating frames).
+
+A slave image is built either from a pre-made EEPROM `.bin` or, preferably,
+compiled from an **ESI XML device** (the parser produces the SII image and the
+CoE object dictionary).
+
+### EmulatedNetwork
+
+`EmulatedNetwork` (`lib/slave/include/kickcat/EmulatedNetwork.h`) routes frames
+between emulated ESCs as a physical network would:
+
+- Explicit port-to-port wiring (default is a daisy-chained line topology).
+- Frame walk in physical EtherCAT port order, branching depth-first.
+- Head and tail master injection points for cable redundancy, with ring-closure
+ detection.
+- Runtime wire break/heal (fault injection) via link-state changes.
+- DC forwarding delays computed from the topology.
+
+### Current limitations
+
+- No interrupt emulation.
+- See the matrix in [FEATURES.md](FEATURES.md) for DC and redundancy status.
+
+---
+
+## Run modes
+
+### 1. In-process loopback (simplest)
+
+The master `Bus` and the emulated slave live in the **same process**, connected
+by `kickcat::LoopbackSocket` (`lib/include/kickcat/LoopbackSocket.h`). No network
+interface, no `/dev/shm`, no second terminal. Each master frame is run through
+the slave and the slave is ticked once. This is the recommended starting point
+and the easiest to debug (single process, single thread).
+
+Canonical example -- `examples/master/simulated_bus`:
+
+```bash
+./build/examples/master/simulated_bus/simulated_bus \
+ -f examples/slave/nuttx/lan9252/freedom-k64f/freedom-k64f.xml -t Board
+```
+
+`-f` takes any vendor ESI XML and `-t` selects the device by its ``
+(omit `-t` to use the first device in the file). It builds the selected device,
+drives INIT -> PRE_OP -> SAFE_OP -> OPERATIONAL, and exchanges process data --
+all in a short example you can read top to bottom.
+
+Beckhoff publish ESI files for their devices at
+;
+most vendors ship the matching ESI XML with their hardware.
+
+`test/integration/bench/esi_boot` uses the same loopback to boot an entire ESI
+catalog in parallel (a good template for batch/regression use).
+
+### 2. Two-process over a TAP socket (network_simulator)
+
+`network_simulator` runs the slaves in their own process and exposes them on a
+shared-memory **TAP socket**; a separate master process connects to the other
+end. This is closer to a real two-node setup and lets an unmodified master
+example run against the simulator.
+
+```bash
+# Terminal 1 -- the simulator is the TAP server (start it first):
+./build/simulation/network_simulator -i tap:server -s simulation/slave_configs/freedom-k64f.json
+
+# Terminal 2 -- the master is the TAP client:
+sudo ./build/examples/master/easycat/easycat_example -i tap:client
+```
+
+To boot from an ESI device instead, point a config's `esi` key at your vendor's
+ESI XML (see the schema below).
+
+Chain several slaves by passing multiple configs:
+
+```bash
+./build/simulation/network_simulator -i tap:server \
+ -s simulation/slave_configs/freedom-k64f.json simulation/slave_configs/xmc4800.json
+```
+
+#### Named TAP segments
+
+`tap:server` / `tap:client` use the default shared-memory name. Append `:`
+to run independent server/client pairs side by side:
+
+```bash
+./build/simulation/network_simulator -i tap:server:busA -s ... # one bus
+./build/examples/master/.../example -i tap:client:busA # its master
+```
+
+#### Different machines
+
+If the master and the simulator run on **different machines**, use real network
+interfaces or a virtual Ethernet pair instead of a TAP socket:
+
+```bash
+# Create a virtual Ethernet pair (Linux, same machine, alternative to TAP)
+sudo ./simulation/create_virtual_ethernet.sh create veth
+```
+
+---
+
+## Slave config schema (JSON)
+
+One JSON object per slave file. Provide **exactly one** source of the slave
+image -- `esi` or `eeprom`:
+
+| Key | Type | Notes |
+|----------------|--------|--------------------------------------------------------------------|
+| `esi` | string | Path to an ESI XML (relative to the config dir). Compiles the SII + CoE dictionary. |
+| `device_type` | string | With `esi`: pick the device by `` (e.g. `"EL1008"`). |
+| `product_code` | uint32 | With `esi`: pick the device by product code. |
+| `revision_no` | uint32 | With `esi`: pick the device by revision. |
+| `eeprom` | string | Path to a raw EEPROM `.bin` (alternative to `esi`). |
+| `coe_xml` | string | With `eeprom`: optional CoE dictionary XML for the mailbox. |
+
+When several `esi` device filters match, the first match is used. With `esi`,
+the CoE mailbox (if the device declares CoE) is built from the same device, so
+`coe_xml` is not needed.
+
+Examples live in `simulation/slave_configs/`.
diff --git a/docs/TOOLS.md b/docs/TOOLS.md
new file mode 100644
index 00000000..05a4c11a
--- /dev/null
+++ b/docs/TOOLS.md
@@ -0,0 +1,107 @@
+# Tools and GUIs
+
+KickCAT ships CLI utilities (in `tools/`), two ImGui-based GUIs, and a
+PySide6 application. CLI tools build with the main project; the GUIs are opt-in.
+
+```bash
+cd build && make -j
+ls tools/ # built CLI tools land here
+```
+
+## KickUI (GUI)
+
+ImGui + GLFW dashboard for inspecting, configuring, and operating an EtherCAT
+bus from the master side (`tools/kickui/`). It provides:
+
+- A network **topology view** with per-slave ports and links.
+- **SDO** read/write across data types (integers, reals, strings, raw hex).
+- **PDO** mapping inspection/editing and a real-time process-data view.
+- A **DS402 motor bench** (setpoints, units configuration).
+- An event/error log and an embedded simulator launcher.
+
+Off by default; build it with:
+
+```bash
+./scripts/configure.sh build --with=kickui
+./scripts/setup_build.sh build
+cd build && make -j
+./tools/kickui/kickui
+```
+
+## EEPROM editor (GUI)
+
+ImGui + GLFW structured editor for slave SII/EEPROM images
+(`tools/eeprom_editor/`), with tabs for device info, strings, SyncManagers,
+FMMUs, and PDO mappings. Off by default:
+
+```bash
+./scripts/configure.sh build --with=eeprom_editor
+./scripts/setup_build.sh build
+cd build && make -j
+./tools/eeprom_editor/kickcat_eeprom_editor
+```
+
+## eeprom (CLI)
+
+Read or write EEPROM content from an EtherCAT Slave Controller
+(`tools/eeprom.cc`):
+
+```bash
+# Write EEPROM to the slave at position 0
+sudo ./tools/eeprom -s 0 -c write -f path/to/eeprom.bin -i
+
+# Auto-detect the interface
+sudo ./tools/eeprom -s 0 -c write -f path/to/eeprom.bin -i "?"
+
+# Read EEPROM from the slave (serializes the SII image to the output file)
+sudo ./tools/eeprom -s 0 -c read -f output.bin -i
+```
+
+## scan_topology (CLI)
+
+Enumerate the slaves on the bus and display the topology, including each slave's
+state and per-port DL status.
+
+## check_network_stability (CLI, Linux)
+
+Long-running monitor for packet loss and corruption: broadcast-reads in a loop
+and reports tx/rx counts and error deltas over time.
+
+## od_generator (CLI)
+
+Generate Object Dictionary code from an ESI file (requires
+`ENABLE_ESI_PARSER=ON`):
+
+```bash
+# Generate od_populator.cc from an ESI file
+./tools/od_generator -f your_device.esi
+```
+
+The generated `od_populator.cc` defines `CoE::createOD()` (declared in
+`kickcat/CoE/OD.h`). Add it to your slave application's build and call it:
+
+```cpp
+#include "kickcat/CoE/OD.h"
+
+int main()
+{
+ // ...
+ auto dictionary = CoE::createOD();
+ // ...
+}
+```
+
+You can also write `od_populator.cc` by hand by implementing `CoE::createOD()`.
+See `examples/slave/nuttx/xmc4800/od_populator.cc` and
+`examples/slave/nuttx/lan9252/freedom-k64f/od_populator.cc` for references.
+
+## ethercat_gui (Python, PySide6)
+
+A pure-Python GUI for master bus control, shipped with the Python package.
+
+Requirements: Python 3, PySide6, and the `kickcat` package
+(`pip install -e .` from the project root).
+
+```bash
+python -m tools.ethercat_gui -i enp8s0
+```
diff --git a/doc/architecture.md b/docs/architecture.md
similarity index 100%
rename from doc/architecture.md
rename to docs/architecture.md
diff --git a/doc/freedom-demo.gif b/docs/freedom-demo.gif
similarity index 100%
rename from doc/freedom-demo.gif
rename to docs/freedom-demo.gif
diff --git a/doc/kickCAT_logo_dark_mode.png b/docs/kickCAT_logo_dark_mode.png
similarity index 100%
rename from doc/kickCAT_logo_dark_mode.png
rename to docs/kickCAT_logo_dark_mode.png
diff --git a/doc/kickCAT_logo_light_mode.png b/docs/kickCAT_logo_light_mode.png
similarity index 100%
rename from doc/kickCAT_logo_light_mode.png
rename to docs/kickCAT_logo_light_mode.png
diff --git a/doc/multi-slave-easycat-output.gif b/docs/multi-slave-easycat-output.gif
similarity index 100%
rename from doc/multi-slave-easycat-output.gif
rename to docs/multi-slave-easycat-output.gif
diff --git a/doc/multi-slave-example.png b/docs/multi-slave-example.png
similarity index 100%
rename from doc/multi-slave-example.png
rename to docs/multi-slave-example.png
diff --git a/simulation/README.md b/simulation/README.md
index 117dbdb3..76a9b886 100644
--- a/simulation/README.md
+++ b/simulation/README.md
@@ -1,86 +1,9 @@
# KickCAT simulator
-Run a master against emulated EtherCAT slaves with no physical hardware. Each
-emulated slave is an `EmulatedESC` (the ESC registers, SyncManagers, FMMUs and
-EEPROM) driven by the slave stack (`Slave` + `PDO` + optional CoE mailbox). A
-slave is built either from a pre-made EEPROM `.bin` or, preferably, **compiled
-from an ESI XML device** (the parser produces the SII image and the CoE object
-dictionary).
+Run a master against emulated EtherCAT slaves with no physical hardware.
-There are two ways to wire a master to emulated slaves.
+The full guide -- emulator engine (`EmulatedESC` / `EmulatedNetwork`), the
+in-process and two-process run modes, and the JSON slave-config schema -- lives
+in [../docs/SIMULATION.md](../docs/SIMULATION.md).
-## 1. In-process loopback (simplest)
-
-Master `Bus` and the emulated slave live in the **same process**, connected by
-`kickcat::LoopbackSocket` (`lib/include/kickcat/LoopbackSocket.h`). No network
-interface, no `/dev/shm`, no second terminal. Each master frame is run through
-the slave and the slave is ticked once. This is the recommended starting point
-and the easiest to debug (single process, single thread).
-
-Canonical example — `examples/master/simulated_bus`:
-
-```bash
-./build/examples/master/simulated_bus/simulated_bus -f "Beckhoff EL1xxx.xml" -t EL1008
-```
-
-It builds the selected device, drives INIT → PRE_OP → SAFE_OP → OPERATIONAL, and
-exchanges process data — all in ~150 lines you can read top to bottom.
-
-`test/integration/bench/esi_boot` uses the same loopback to boot an entire ESI
-catalog in parallel (a good template for batch/regression use).
-
-## 2. Two-process over a TAP socket (`network_simulator`)
-
-`network_simulator` runs the slaves in their own process and exposes them on a
-shared-memory **TAP socket**; a separate master process connects to the other
-end. Closer to a real two-node setup; useful for CI and for running an unmodified
-master example against the simulator.
-
-```bash
-# Terminal 1 — the simulator is the TAP server (start it first):
-./build/simulation/network_simulator -i tap:server -s simulation/slave_configs/freedom-k64f.json
-
-# Terminal 2 — the master is the TAP client:
-sudo ./build/examples/master/easycat/easycat_example -i tap:client
-```
-
-To boot from an ESI device instead, point a config's `esi` key at your vendor's
-ESI XML (see the schema below); the in-process example above is the quickest way
-to try one.
-
-Chain several slaves by passing multiple configs, or repeat one with `-n N`:
-
-```bash
-./build/simulation/network_simulator -i tap:server \
- -s simulation/slave_configs/freedom-k64f.json simulation/slave_configs/xmc4800.json
-```
-
-### Named TAP segments
-
-`tap:server` / `tap:client` use the default shared-memory name. Append `:`
-to run independent server/client pairs side by side:
-
-```bash
-./build/simulation/network_simulator -i tap:server:busA -s ... # one bus
-./build/examples/master/.../example -i tap:client:busA # its master
-```
-
-## Slave config schema (JSON)
-
-One JSON object per slave file. Provide **exactly one** source of the slave
-image — `esi` or `eeprom`:
-
-| Key | Type | Notes |
-|----------------|--------|--------------------------------------------------------------------|
-| `esi` | string | Path to an ESI XML (relative to the config dir). Compiles the SII + CoE dictionary. |
-| `device_type` | string | With `esi`: pick the device by `` (e.g. `"EL1008"`). |
-| `product_code` | uint32 | With `esi`: pick the device by product code. |
-| `revision_no` | uint32 | With `esi`: pick the device by revision. |
-| `eeprom` | string | Path to a raw EEPROM `.bin` (alternative to `esi`). |
-| `coe_xml` | string | With `eeprom`: optional CoE dictionary XML for the mailbox. |
-
-When several `esi` device filters match, the first match is used. With `esi`,
-the CoE mailbox (if the device declares CoE) is built from the same device, so
-`coe_xml` is not needed.
-
-Examples live in `simulation/slave_configs/`.
+Ready-made slave configurations are in `slave_configs/`.
diff --git a/tools/eeprom.cc b/tools/eeprom.cc
index 6c0bf342..4c4c85eb 100644
--- a/tools/eeprom.cc
+++ b/tools/eeprom.cc
@@ -1,5 +1,4 @@
// Tool to dump and flash the eeprom of a slave on the bus.
-// Current state: POC, can only dump eeprom file.
#include "kickcat/Bus.h"
#include "kickcat/Link.h"
diff --git a/uncrustify.cfg b/uncrustify.cfg
new file mode 100644
index 00000000..af5c05ec
--- /dev/null
+++ b/uncrustify.cfg
@@ -0,0 +1,129 @@
+# KickCAT coding style — uncrustify config
+# Tested with Uncrustify 0.83.x
+#
+# Philosophy: enforce the mechanical, unambiguous parts of the house style
+# (4-space indent, indented namespaces, Allman braces, spacing around keywords
+# and operators, pointer placement) and deliberately leave judgement calls to
+# the author. In particular, hand-aligned "tabular" blocks (struct/enum value
+# columns, grouped assignments, trailing comments) are PRESERVED rather than
+# imposed or destroyed: operator spacing uses "add" (ensure a space exists, do
+# not collapse extra ones) and the align_* passes are disabled.
+
+#
+# Indentation
+#
+indent_columns = 4
+indent_with_tabs = 0 # spaces only
+indent_namespace = true # body of a namespace is indented
+indent_class = true # body of a class is indented
+indent_access_spec = 5 # public:/private: at the class-brace column
+ # (absolute col = value-1; assumes the
+ # common "one namespace deep" nesting)
+indent_switch_case = 4 # case labels indented inside switch
+indent_label = 1
+indent_continue = 0 # continuations align to the open paren
+
+# Lambdas assigned to a variable (auto x = [...]{ ... };) keep their brace and
+# body at the enclosing statement indent rather than aligned under the capture.
+indent_align_assign = false
+indent_off_after_assign = true
+
+#
+# Braces: Allman (brace on its own line) everywhere
+#
+nl_fdef_brace = add # function definition
+nl_if_brace = add
+nl_brace_else = add # else on its own line
+nl_else_brace = add
+nl_elseif_brace = add
+nl_for_brace = add
+nl_while_brace = add
+nl_do_brace = add
+nl_brace_while = remove
+nl_switch_brace = add
+nl_namespace_brace = add
+nl_class_brace = add
+nl_struct_brace = add
+nl_union_brace = add
+nl_enum_brace = add
+
+#
+# Newline / blank-line cleanup
+#
+nl_max = 3 # allow at most 2 consecutive blank lines
+nl_end_of_file = force # trailing newline
+nl_end_of_file_min = 1
+eat_blanks_before_close_brace = true
+eat_blanks_after_open_brace = true
+
+#
+# Spacing around keywords and parentheses (unambiguous)
+#
+sp_before_sparen = force # if (, switch (, for (, while (
+sp_inside_sparen = remove
+sp_inside_paren = remove
+sp_inside_fparen = remove
+sp_paren_paren = remove
+sp_before_semi = remove
+sp_after_semi_for = force
+sp_after_type = ignore # preserve hand-aligned declaration columns
+sp_after_cast = remove # static_cast(x)
+sp_inside_angle = remove
+sp_before_angle = remove
+sp_inside_square = remove
+sp_angle_shift = remove # keep nested closers together: vector>
+sp_permit_cpp11_shift = true # required for sp_angle_shift to collapse '> >'
+
+#
+# Pointer placement: star hugs the type (void* p, char const* s).
+# Reference (&) spacing is deliberately NOT set: the codebase already writes
+# "T& name" consistently, and forcing "remove before byref" makes uncrustify
+# misparse bitwise '&' (mode & FLAG) — so references are simply left as written.
+#
+sp_before_ptr_star = remove
+sp_after_ptr_star = add # "add" (not "force") preserves aligned pointer columns
+sp_before_ptr_star_func = remove
+sp_after_ptr_star_func = add
+sp_between_ptr_star = remove
+
+#
+# Operator spacing: "add" ensures a space without collapsing hand-alignment,
+# so tabular blocks the author aligned by hand survive a reformat untouched.
+#
+sp_assign = add
+sp_after_comma = add
+sp_before_comma = remove
+sp_arith = add
+sp_bool = add
+sp_compare = add
+
+#
+# Alignment passes left OFF: alignment is an author judgement call (blur).
+# Disabling them means uncrustify neither imposes new alignment nor destroys
+# existing aligned blocks (paired with the "add" operator spacing above).
+#
+align_assign_span = 0
+align_var_def_span = 0
+align_struct_init_span = 0
+align_right_cmt_span = 0
+
+#
+# One-line bodies are a deliberate readability device here (inline accessors,
+# tabular "case X: { return ...; }" rows). Leave every existing one-liner as the
+# author wrote it instead of exploding it to Allman form.
+#
+nl_func_leave_one_liners = true
+nl_getset_leave_one_liners = true
+nl_class_leave_one_liners = true
+nl_enum_leave_one_liners = true
+nl_assign_leave_one_liners = true
+nl_if_leave_one_liners = true
+nl_for_leave_one_liners = true
+nl_while_leave_one_liners = true
+nl_do_leave_one_liners = true
+nl_cpp_lambda_leave_one_liners = true
+
+mod_full_brace_if = ignore
+mod_full_brace_for = ignore
+mod_full_brace_while = ignore
+mod_remove_extra_semicolon = true