iolinki. Hardware-Agnostic IO-Link Stack
I developed IOlink devices when I was working at IFM. I still remember crafting IODDs by hand. And I was wondering how hard will it be to build a stack for it by myslef? The industrial automation world is standardizing on IO-Link (IEC 61131-9). Yet, there were no open-source full featured IO-Link stacks to support it. So here it is.
I built iolinki to prove that an industrial bus stack can and SHOULD be modern, testable, and completely decoupled from hardware.
Source Code: github.com/w1ne/iolinki
Key Architecture Decisions
1. Hardware Independence
iolinki takes an approach of Pure Abstraction. No hardware specific code is in the stack.
The stack interacts with the hardware solely through a iolink_phy_api_t structure of function pointers.
typedef struct {
int (*init)(void);
int (*set_mode)(iolink_mode_t mode);
int (*send_byte)(uint8_t byte);
int (*read_byte)(uint8_t *byte);
// ...
} iolink_phy_api_t;
This boundary means the protocol logic (dll.c) cannot access hardware registers. Because of that, we can implement the best solution to fast and safe development, Simulation.
2. Test-Driven Development (TDD)
We use the PHY in Linux as an interface to communicate with the IO-Link Master.
iolinki was developed using a Virtual PHY that pipes data to a Python-based IO-Link Master simulation (tools/virtual_master).
This allows us to run automated conformance tests in a CI/CD pipeline (GitHub Actions) without a single piece of real hardware connected.
Conformance Coverage
We validate against IO-Link V1.1.5 specification requirements.
- State Machine All transitions (Startup → Preoperate → Operate).
- Timing Cycle times and wake-up pulses measured to microsecond precision in simulation.
- ISDU Full coverage of all 12 mandatory indices (0x0010 Vendor Name, etc.).
- Error Injection We inject CRC errors and timeouts to verify the stack’s recovery logic.
3. Zero dynamic memory safety
iolinki uses a static memory allocation.
- No
malloc/free. All buffers are allocated at compile time. - Deterministic Execution. The
iolink_process()loop is designed to have a bounded execution time. This makes it safe for real-time control loops.
4. Zephyr RTOS Integration
While the core runs bare-metal, iolinki can be used on Zephyr.
- Logging. Uses Zephyr’s logging subsystem for transparent debugging.
- Shell. Exposes stack status and statistics via the Zephyr console.
Technical Deep Dive
The heart of the stack is the Data Link Layer (DLL) state machine. It handles “M-Sequence” exchange.
- STARTUP The stack waits for the Wake-Up pulse (WURQ).
- PREOPERATE The Master requests parameters (MinCycleTime, FrameCapability) at 230.4 kbaud (COM3) or lower.
- OPERATE The stack enters the cyclic Process Data (PD) exchange.
This transition logic is tricky due to strict timing requirements (e.g., specific response windows). We use unit-testing for the state machine with cmocka to ensure that edge cases—like a Master dropping out mid-handshake—are handled correctly.
iolinkiuses modern software engineering standards such CI/CD, TDD, and modular architecture. It provides a robust, verified foundation for building the next gen of smart sensors. And it’s open source. If you want to build a sensor, find me at andrii@shylenko.com.