DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
iolink.h
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file iolink.h
6 * @brief IO-Link (SDCI, IEC 61131-9) data-link message codec (DETWS_ENABLE_IOLINK).
7 *
8 * IO-Link is the point-to-point 3-wire serial link to smart sensors / actuators. This codec
9 * implements the data-link **message layer**: the M-sequence Control octet (MC), the
10 * checksum / M-sequence-type octet (CKT) of a master message, the checksum / status octet
11 * (CKS) of a device reply, and the SDCI message checksum that protects both directions.
12 *
13 * The checksum is the part everyone gets wrong, so it is implemented straight from the spec
14 * (IO-Link Interface and System Specification v1.1.4, Annex A.1.6): a 0x52 seed XORed octet
15 * by octet across the message (the check octet included with its checksum bits 0), then the
16 * 8-to-6-bit compression of equation (A.1). `iol_finalize` writes it into the check octet and
17 * `iol_verify` checks it.
18 *
19 * Scope: the message / DL layer. The per-type M-sequence octet layout (process + on-request
20 * data widths) is the device's profile, and the ISDU on-request service framing layers on top;
21 * lay those octets out per your device, then finalize / verify with this codec. The wire is a
22 * UART at 4.8 / 38.4 / 230.4 kbit/s through an IO-Link transceiver (e.g. MAX14819 / L6360);
23 * pure and host-tested.
24 *
25 * @author Douglas Quigg (dstroy0)
26 * @date 2026
27 */
28
29#ifndef DETERMINISTICESPASYNCWEBSERVER_IOLINK_H
30#define DETERMINISTICESPASYNCWEBSERVER_IOLINK_H
31
32#include "ServerConfig.h"
33
34#if DETWS_ENABLE_IOLINK
35
36#include <stddef.h>
37#include <stdint.h>
38
39#define IOL_CHECKSUM_SEED 0x52u ///< checksum seed XORed with the first octet (spec A.1.6)
40
41// M-sequence Control (MC) octet fields.
42#define IOL_MC_READ 0x80u ///< bit 7 set => read access
43#define IOL_MC_WRITE 0x00u ///< bit 7 clear => write access
44#define IOL_CH_PROCESS 0u ///< communication channel: Process Data
45#define IOL_CH_PAGE 1u ///< communication channel: Page (direct parameters)
46#define IOL_CH_DIAGNOSIS 2u ///< communication channel: Diagnosis
47#define IOL_CH_ISDU 3u ///< communication channel: ISDU (on-request data)
48
49// M-sequence types (CKT bits 7-6).
50#define IOL_MSEQ_TYPE_0 0u
51#define IOL_MSEQ_TYPE_1 1u
52#define IOL_MSEQ_TYPE_2 2u
53
54// Checksum / status (CKS) octet flags.
55#define IOL_CKS_EVENT 0x80u ///< bit 7: Device has an Event pending
56#define IOL_CKS_PD_INVALID 0x40u ///< bit 6: Process Data invalid
57
58#define IOL_CHECK_HIGH_MASK 0xC0u ///< the non-checksum (type / status) bits of a check octet
59#define IOL_CHECK_SUM_MASK 0x3Fu ///< the 6-bit checksum field of a check octet
60
61// --- control-octet builders / decoders ---
62
63/** @brief Build the M-sequence Control octet from access / channel / address (5-bit). */
64uint8_t iol_mc(bool read, uint8_t channel, uint8_t address);
65
66/** @brief True if the MC octet requests a read. */
67bool iol_mc_is_read(uint8_t mc);
68
69/** @brief Communication channel from an MC octet (IOL_CH_*). */
70uint8_t iol_mc_channel(uint8_t mc);
71
72/** @brief Address (5-bit) from an MC octet. */
73uint8_t iol_mc_address(uint8_t mc);
74
75/** @brief Build a CKT octet from an M-sequence type and a 6-bit checksum (use 0 before finalize). */
76uint8_t iol_ckt(uint8_t mseq_type, uint8_t checksum6);
77
78/** @brief Build a CKS octet from the Event / PD-invalid flags and a 6-bit checksum. */
79uint8_t iol_cks(bool event, bool pd_invalid, uint8_t checksum6);
80
81// --- checksum (spec A.1.6) ---
82
83/**
84 * @brief The compressed 6-bit SDCI checksum over @p msg (the check octet must already have its
85 * low 6 bits set to 0). Seed 0x52, XOR every octet, then compress 8->6 per equation (A.1).
86 */
87uint8_t iol_checksum6(const uint8_t *msg, size_t len);
88
89/**
90 * @brief Finalize a message in place: compute the checksum over @p msg (treating the check octet
91 * at @p check_idx with checksum bits 0) and OR it into that octet, preserving its type / status
92 * bits. Returns the finalized check octet.
93 */
94uint8_t iol_finalize(uint8_t *msg, size_t len, size_t check_idx);
95
96/**
97 * @brief Verify a received message: recompute the checksum (masking off the check octet's
98 * checksum bits) and compare it to the 6-bit checksum carried in the check octet at @p check_idx.
99 */
100bool iol_verify(const uint8_t *msg, size_t len, size_t check_idx);
101
102#endif // DETWS_ENABLE_IOLINK
103#endif // DETERMINISTICESPASYNCWEBSERVER_IOLINK_H
User-facing configuration for DeterministicESPAsyncWebServer.