iolinki-master API Reference
Source snapshot: docs/API.md,
d23fd3034c02.
A guided tour of the public API in
include/iolinki_master/master.h. Every
function returns a named result constant — IOLINK_MASTER_STATUS_OK (0),
IOLINK_MASTER_STATUS_PENDING (1), or a negative IOLINK_MASTER_ERR_* /
..._ISDU_ERR_* / ..._SIO_ERR_* / ..._PARAM_ERR_* code. Check every return.
All state is caller-owned: you allocate iolink_master_port_t (a fixed-size opaque
union, 1280 B) or iolink_master_controller_t (32 B). There is no heap.
1. Configuration and init
Fill an iolink_master_config_t, then init a port against a PHY:
int iolink_master_init(iolink_master_port_t* port,
const iolink_phy_api_t* phy,
const iolink_master_config_t* config);
Key config fields (iolink_master_config_t): port_mode
(IOLINK_MASTER_PORT_MODE_IOLINK / _DI / _DQ / _DEACTIVATED), m_seq_type,
baudrate, min_cycle_time, pd_in_len / pd_out_len, auto_baudrate,
response_timeout_100us, wake_retry_limit, the identity fields
(validate_device_info, inspection_level, expected_vendor_id,
expected_device_id), the event callbacks (§6), and the PHY adapter hooks
(set_mode_checked, set_baudrate_checked, flush_rx, prepare_tx,
prepare_rx, read_cq_line / read_cq_line_checked, wake_up — see
PORTING.md).
Lifetime: the config is copied into the port, but the PHY is retained by pointer. The
iolink_phy_api_tmust outlive the port — never pass a stack temporary.
Related: iolink_master_validate_phy_contract(phy, config) checks the PHY/config
pair is complete for real hardware; iolink_master_restart(port) restarts startup;
iolink_master_get_state(port) returns the current iolink_master_state_t.
2. The tick / scheduler model
The core owns no clock. You drive it and supply time.
iolink_master_process(port)— send one pending startup/preoperate/operate action.iolink_master_poll_rx(port)— decode available RX bytes; returns the decoded frame count,OKwhen no byte is available, orINVALID_ARG/ERR_FRAME/ERR_CHECKSUM.iolink_master_tick(port, response_timeout)— bool-flag tick.iolink_master_tick_event(port, event)— explicit event tick (IOLINK_MASTER_TICK_NONE/_CYCLE_DUE/_RESPONSE_TIMEOUT).iolink_master_tick_at(port, event, now_100us)— as above, applying monotonic 100µsmin_cycle_timepacing.iolink_master_get_next_tick_time(port, now_100us, &out_next_100us)— when the port is next due, for your hardware timer.iolink_master_on_timeout(port)— advance the retry policy on a response timeout; returnsOK,PENDINGwhile retrying, orERR_RETRY_LIMIT.iolink_master_get_timing(port, &timing)— read-only scheduler snapshot.
response_timeout_100us controls the response deadline; min_cycle_time controls
cycle spacing (a zero response timeout falls back to min_cycle_time).
3. Process data
int iolink_master_set_pd_out(iolink_master_port_t* port, const uint8_t* data, uint8_t len);
int iolink_master_get_pd_in(const iolink_master_port_t* port,
uint8_t* buffer, uint8_t buffer_len, uint8_t* out_len);
int iolink_master_get_od_status(const iolink_master_port_t* port, uint8_t* status);
set_pd_out returns ERR_BUFFER_TOO_SMALL if len does not match the configured
PD-out size. get_pd_in returns PENDING until valid PD has arrived.
4. Device identity and Direct Parameter Page 1
iolink_master_parse_direct_parameter_page1(page, len, &info)— decode a raw page-1 buffer intoiolink_master_device_info_t.iolink_master_apply_direct_parameter_page1(port, page, len)— parse and store.iolink_master_get_device_info(port, &info)/iolink_master_read_device_info(port).iolink_master_validate_device_info(port)— VendorID/DeviceID vs configured expectations at the selectedinspection_level(NO_CHECK/TYPE_COMP/IDENTICAL; the SerialNumber leg ofIDENTICALis not yet wired).iolink_master_select_config_from_device_info(&info, &config)andiolink_master_validate_config_against_device_info(&info, &config).iolink_master_decode_min_cycle_time_100us(octet)— MasterCycleTime octet →100µs.
5. ISDU and services
All service calls are non-blocking state machines: they return OK when complete,
PENDING while active, INVALID_ARG, or a domain error.
int iolink_master_read_isdu (port, index, subindex, data, &len); /* len: in=cap, out=actual */
int iolink_master_write_isdu(port, index, subindex, data, len);
int iolink_master_verify_isdu(port, index, subindex, expected, len);
Data Storage: iolink_master_read_data_storage, ..._write_data_storage,
..._restore_data_storage, ..._verify_data_storage. Block parameterization:
iolink_master_begin_parameter_download / ..._end_parameter_download /
..._begin_parameter_upload / ..._end_parameter_upload /
..._store_parameter_download / ..._write_parameter_block. Status:
iolink_master_read_detailed_device_status. ISDU errors use
IOLINK_MASTER_ISDU_ERR_* (BUFFER_TOO_SMALL, BUSY, DEVICE, INVALID_STATE,
VERIFY_FAILED).
6. Events
Poll model: read iolink_master_diagnostics_t.event_pending, then:
int iolink_master_read_event_code(port, &event_code);
int iolink_master_ack_event(port, &event_code); /* read == explicit ack */
int iolink_master_read_event_details(port, events, max_events, &out_count);
read_event_details writes at most max_events iolink_master_event_t
({qualifier, type, code}) and returns BUFFER_TOO_SMALL rather than overrunning.
Dispatch model (optional): set event_pending_handler and/or event_handler in the
config (with event_user passed through). event_pending_handler fires on the
rising edge of the OD Event flag during a cyclic response; event_handler fires
once per decoded event. Both NULL keeps poll-only behavior.
7. Diagnostics
int iolink_master_get_diagnostics(const iolink_master_port_t* port,
iolink_master_diagnostics_t* diagnostics);
uint8_t iolink_master_get_device_status(const iolink_master_port_t* port);
iolink_master_diagnostics_t carries od_status, event_pending,
rx_retry_count, checksum_errors, send_errors, response_timeouts,
cycle_slips, last/max cycle jitter (100µs), supply_voltage_mv, short_circuit
(sampled from PHY hooks when present), link_quality_percent, last_service_result,
last_event_count/last_event_code, and last_isdu_error.
8. SIO DI/DQ
int iolink_master_set_dq(iolink_master_port_t* port, bool level); /* DQ mode */
int iolink_master_get_di(const iolink_master_port_t* port, bool* level); /* DI mode */
int iolink_master_set_port_mode(iolink_master_port_t* port, iolink_master_port_mode_t mode);
Wrong-mode / unsupported-PHY calls return IOLINK_MASTER_SIO_ERR_WRONG_MODE /
..._UNSUPPORTED_PHY. Switching to IO-Link mode restarts startup on the port.
9. Master Command helpers
iolink_master_encode_master_command(read, channel, address) composes a Master
Command octet; iolink_master_mc_is_read / ..._mc_channel / ..._mc_address
decode one. Channels: IOLINK_MASTER_MC_CHANNEL_PROCESS / _PAGE / _DIAGNOSIS /
_ISDU.
10. Multi-port controller
int iolink_master_controller_init(controller, ports, port_count, phys, configs);
int iolink_master_controller_tick(controller, response_timeouts); /* bool[] */
int iolink_master_controller_tick_events(controller, events); /* tick_event[] */
int iolink_master_controller_tick_at(controller, now_100us);
int iolink_master_controller_get_port_count(controller, &out_count);
int iolink_master_controller_get_port(controller, index, &out_port);
int iolink_master_controller_get_next_tick_time(controller, now_100us, &out_next_100us);
Same lifetime contract as iolink_master_init: the phys array (and the PHYs it
points to) and the ports array must outlive the controller. A failing port
returns the first negative result without corrupting its siblings.
Minimal example
Drives one port from startup into OPERATE and reads back process data. Compiles
against the real API (mirrors examples/master_loopback_demo.c; the PHY here is a
trivial stub — a real PHY talks to a transceiver, see PORTING.md).
#include <stdio.h>
#include "iolinki/phy.h"
#include "iolinki_master/master.h"
/* A real PHY drives a transceiver; these stubs just satisfy the contract. */
static int phy_init(void* u) { (void)u; return 0; }
static void phy_set_mode(void* u, iolink_phy_mode_t m) { (void)u; (void)m; }
static void phy_set_baud(void* u, iolink_baudrate_t b) { (void)u; (void)b; }
static int phy_send(void* u, const uint8_t* d, size_t n){ (void)u; (void)d; return (int)n; }
static int phy_recv(void* u, uint8_t* b) { (void)u; (void)b; return 0; }
static const iolink_phy_api_t phy = {
.init = phy_init, .set_mode = phy_set_mode,
.set_baudrate = phy_set_baud, .send = phy_send, .recv_byte = phy_recv,
};
int main(void)
{
iolink_master_port_t port; /* caller-owned, no heap */
iolink_master_config_t config = {
.port_mode = IOLINK_MASTER_PORT_MODE_IOLINK,
.m_seq_type = IOLINK_MASTER_M_SEQ_TYPE_2_1,
.baudrate = IOLINK_BAUDRATE_COM3,
.min_cycle_time = 20U,
.pd_in_len = 1U,
.pd_out_len = 1U,
.auto_baudrate = false,
};
uint8_t pd_out[1] = { 0x11U };
uint8_t pd_in[1] = { 0U };
uint8_t pd_in_len = sizeof(pd_in);
if (iolink_master_init(&port, &phy, &config) != IOLINK_MASTER_STATUS_OK) {
return 1;
}
if (iolink_master_set_pd_out(&port, pd_out, sizeof(pd_out)) != IOLINK_MASTER_STATUS_OK) {
return 1;
}
/* Drive the port: process() sends, poll_rx() decodes responses. A real
* integration paces these from a 100us timer via iolink_master_tick_at(). */
iolink_master_process(&port);
(void)iolink_master_poll_rx(&port);
if (iolink_master_get_pd_in(&port, pd_in, sizeof(pd_in), &pd_in_len)
== IOLINK_MASTER_STATUS_OK) {
printf("PD in: 0x%02X\n", pd_in[0]);
}
return 0;
}
Build it against the master library (which links the sibling iolinki frame/CRC
helpers) — see CONTRIBUTING.md and the runnable
examples/master_loopback_demo.c / examples/master_4port_controller_demo.c.