DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
iolink.cpp
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.cpp
6 * @brief IO-Link (SDCI) data-link message codec (pure, host-tested).
7 */
8
10
11#if DETWS_ENABLE_IOLINK
12
13uint8_t iol_mc(bool read, uint8_t channel, uint8_t address)
14{
15 return (uint8_t)((read ? IOL_MC_READ : 0u) | ((channel & 0x03u) << 5) | (address & 0x1Fu));
16}
17
18bool iol_mc_is_read(uint8_t mc)
19{
20 return (mc & IOL_MC_READ) != 0;
21}
22
23uint8_t iol_mc_channel(uint8_t mc)
24{
25 return (uint8_t)((mc >> 5) & 0x03u);
26}
27
28uint8_t iol_mc_address(uint8_t mc)
29{
30 return (uint8_t)(mc & 0x1Fu);
31}
32
33uint8_t iol_ckt(uint8_t mseq_type, uint8_t checksum6)
34{
35 return (uint8_t)(((mseq_type & 0x03u) << 6) | (checksum6 & IOL_CHECK_SUM_MASK));
36}
37
38uint8_t iol_cks(bool event, bool pd_invalid, uint8_t checksum6)
39{
40 return (uint8_t)((event ? IOL_CKS_EVENT : 0u) | (pd_invalid ? IOL_CKS_PD_INVALID : 0u) |
41 (checksum6 & IOL_CHECK_SUM_MASK));
42}
43
44// Compress the 8-bit XOR result to 6 bits per IO-Link spec v1.1.4 Annex A.1.6 equation (A.1).
45static uint8_t compress6(uint8_t b)
46{
47 uint8_t b0 = b & 1u, b1 = (b >> 1) & 1u, b2 = (b >> 2) & 1u, b3 = (b >> 3) & 1u;
48 uint8_t b4 = (b >> 4) & 1u, b5 = (b >> 5) & 1u, b6 = (b >> 6) & 1u, b7 = (b >> 7) & 1u;
49 uint8_t d5 = (uint8_t)(b7 ^ b5 ^ b3 ^ b1);
50 uint8_t d4 = (uint8_t)(b6 ^ b4 ^ b2 ^ b0);
51 uint8_t d3 = (uint8_t)(b7 ^ b6);
52 uint8_t d2 = (uint8_t)(b5 ^ b4);
53 uint8_t d1 = (uint8_t)(b3 ^ b2);
54 uint8_t d0 = (uint8_t)(b1 ^ b0);
55 return (uint8_t)((d5 << 5) | (d4 << 4) | (d3 << 3) | (d2 << 2) | (d1 << 1) | d0);
56}
57
58uint8_t iol_checksum6(const uint8_t *msg, size_t len)
59{
60 uint8_t x = IOL_CHECKSUM_SEED; // seed XORed with the first octet, then every octet
61 for (size_t i = 0; i < len; i++)
62 x ^= msg[i];
63 return compress6(x);
64}
65
66uint8_t iol_finalize(uint8_t *msg, size_t len, size_t check_idx)
67{
68 if (!msg || check_idx >= len)
69 return 0;
70 msg[check_idx] = (uint8_t)(msg[check_idx] & IOL_CHECK_HIGH_MASK); // zero the checksum field
71 uint8_t c6 = iol_checksum6(msg, len);
72 msg[check_idx] = (uint8_t)(msg[check_idx] | (c6 & IOL_CHECK_SUM_MASK));
73 return msg[check_idx];
74}
75
76bool iol_verify(const uint8_t *msg, size_t len, size_t check_idx)
77{
78 if (!msg || check_idx >= len)
79 return false;
80 uint8_t x = IOL_CHECKSUM_SEED;
81 for (size_t i = 0; i < len; i++)
82 x ^= (i == check_idx) ? (uint8_t)(msg[i] & IOL_CHECK_HIGH_MASK) : msg[i];
83 return compress6(x) == (uint8_t)(msg[check_idx] & IOL_CHECK_SUM_MASK);
84}
85
86#endif // DETWS_ENABLE_IOLINK