ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
powerlink.h
Go to the documentation of this file.
1// ProtoCore v1.0.16 - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file powerlink.h
6 * @brief Ethernet POWERLINK (EPSG) basic frame codec (PROTOCORE_ENABLE_POWERLINK).
7 *
8 * Ethernet POWERLINK is the EPSG real-time managed-node bus over raw L2 (ethertype 0x88AB, on the
9 * shipped services/fieldbus/rawl2). The Managing Node (MN) runs an isochronous cycle: it multicasts a **SoC**
10 * (Start of Cycle), unicasts a **PReq** (Poll Request) to each Controlled Node (CN), each CN answers with
11 * a **PRes** (Poll Response) carrying its process data, then an **SoA** (Start of Async) opens the async
12 * phase. Every EPL basic frame is:
13 *
14 * [messageType : 1][destination node : 1][source node : 1][payload...]
15 *
16 * This builds and parses those frames (the four cyclic message types + the node addressing), so the MN
17 * schedules the cycle and a CN answers with its PRes process image. Pure, zero heap, no stdlib,
18 * host-testable; the raw-L2 transmit + the isochronous timing (the preempting-task model) are the device
19 * step.
20 */
21
22#ifndef PROTOCORE_POWERLINK_H
23#define PROTOCORE_POWERLINK_H
24
25#include "protocore_config.h" // the entry point: protocore_types.h for the widths
26
27#if PROTOCORE_ENABLE_POWERLINK
28
30
31// This module holds nothing between calls, so it carves no borrow and states none. An entry
32// takes one all the same, and never reads it, so every namespace in the tree is invoked the
33// same way.
34
35/** @brief EPL message types (EPSG DS 301). */
36// POWERLINK message types + node ids: wire bytes, so integer constants in a namespacing struct.
37#define EPL_MSG_SOC 0x01 ///< Start of Cycle (MN -> all, multicast).
38#define EPL_MSG_PREQ 0x03 ///< Poll Request (MN -> CN, unicast).
39#define EPL_MSG_PRES 0x04 ///< Poll Response (CN -> all, multicast, carries process data).
40#define EPL_MSG_SOA 0x05 ///< Start of Async (MN -> all).
41#define EPL_MSG_ASND 0x06 ///< Async Send.
42#define EPL_NODE_BROADCAST 0xFF ///< broadcast node id (SoC/SoA destination).
43#define EPL_NODE_MN 0xF0 ///< the Managing Node id (240).
44
45/** @brief A parsed EPL basic frame (payload points into the input). */
46typedef struct
47{
48 uint8_t msg_type;
49 uint8_t dest;
50 uint8_t source;
51 const uint8_t *payload;
52 size_t payload_len;
53} EplFrame;
54
55/** @brief What build takes: msg_type, dest, source, payload, ... */
56typedef struct
57{
58 uint8_t msg_type;
59 uint8_t dest;
60 uint8_t source;
61 const uint8_t *payload;
62 size_t payload_len;
63 uint8_t *out;
64 size_t cap;
65} PowerlinkBuildArgs;
66
67/** @brief What soc takes: source, out, cap. */
68typedef struct
69{
70 uint8_t source;
71 uint8_t *out;
72 size_t cap;
73} PowerlinkSocArgs;
74
75/** @brief What preq takes: dest_cn, source, pdo, pdo_len, out, cap. */
76typedef struct
77{
78 uint8_t dest_cn;
79 uint8_t source;
80 const uint8_t *pdo;
81 size_t pdo_len;
82 uint8_t *out;
83 size_t cap;
84} PowerlinkPreqArgs;
85
86/** @brief What pres takes: source_cn, pdo, pdo_len, out, cap. */
87typedef struct
88{
89 uint8_t source_cn;
90 const uint8_t *pdo;
91 size_t pdo_len;
92 uint8_t *out;
93 size_t cap;
94} PowerlinkPresArgs;
95
96/** @brief What soa takes: source, payload, payload_len, out, cap. */
97typedef struct
98{
99 uint8_t source;
100 const uint8_t *payload;
101 size_t payload_len;
102 uint8_t *out;
103 size_t cap;
104} PowerlinkSoaArgs;
105
106/** @brief What asnd takes: dest, source, payload, payload_len, out, ... */
107typedef struct
108{
109 uint8_t dest;
110 uint8_t source;
111 const uint8_t *payload;
112 size_t payload_len;
113 uint8_t *out;
114 size_t cap;
115} PowerlinkAsndArgs;
116
117/** @brief What parse takes: frame, len, out. */
118typedef struct
119{
120 const uint8_t *frame;
121 size_t len;
122 EplFrame *out;
123} PowerlinkParseArgs;
124
125/**
126 * @brief Ethernet POWERLINK (EPSG) basic frame codec (PROTOCORE_ENABLE_POWERLINK).
127 *
128 * A caller sets the members a call takes, invokes it through ::Powerlink with the bytes it runs
129 * out of, and reads the outcome off the same handle.
130 *
131 * Powerlink.build_args.msg_type = ...;
132 * Powerlink.build_args.dest = ...;
133 * Powerlink.build_args.source = ...;
134 * Powerlink.build_args.payload = ...;
135 * Powerlink.build_args.payload_len = ...;
136 * Powerlink.build_args.out = ...;
137 * Powerlink.build_args.cap = ...;
138 * Powerlink.build(work);
139 * // Powerlink.n is what the call reports
140 *
141 * @var PowerlinkNs::build_args what build takes: msg_type, dest, source, payload,
142 * @var PowerlinkNs::soc_args what soc takes: source, out, cap
143 * @var PowerlinkNs::preq_args what preq takes: dest_cn, source, pdo, pdo_len, out, cap
144 * @var PowerlinkNs::pres_args what pres takes: source_cn, pdo, pdo_len, out, cap
145 * @var PowerlinkNs::soa_args what soa takes: source, payload, payload_len, out, cap
146 * @var PowerlinkNs::asnd_args what asnd takes: dest, source, payload, payload_len, out,
147 * @var PowerlinkNs::parse_args what parse takes: frame, len, out
148 * @var PowerlinkNs::ok a call's true/false outcome
149 * @var PowerlinkNs::n the frame length (3 + payload_len), or 0 on overflow / bad args
150 * @var PowerlinkNs::build build an EPL basic frame: [messageType][dest][source][payload...]
151 * @var PowerlinkNs::soc convenience: build an SoC (MN -> broadcast, no payload)
152 * @var PowerlinkNs::preq convenience: build a PReq to a CN carrying its output process image
153 * @var PowerlinkNs::pres convenience: build a PRes from a CN carrying its input process ...
154 * @var PowerlinkNs::soa convenience: build an SoA (MN -> broadcast) that opens the ...
155 * @var PowerlinkNs::asnd convenience: build an ASnd (asynchronous send) from source to dest. ...
156 * @var PowerlinkNs::parse parse an EPL basic frame. true if len >= 3 and the message type is ...
157 *
158 * @c work is bytes the CALLER holds. This module reads none of them: it carries nothing
159 * between calls, so there is no state to keep and nothing to wipe. The parameter is there so
160 * a caller drives every namespace the same way.
161 */
162typedef struct
163{
164 PowerlinkBuildArgs build_args;
165 PowerlinkSocArgs soc_args;
166 PowerlinkPreqArgs preq_args;
167 PowerlinkPresArgs pres_args;
168 PowerlinkSoaArgs soa_args;
169 PowerlinkAsndArgs asnd_args;
170 PowerlinkParseArgs parse_args;
171 proto_bool ok;
172 size_t n;
173} PowerlinkVars;
174
175/** @brief The operands and the outcome. */
176extern PowerlinkVars PowerlinkV;
177
178/** @brief The entries. */
179typedef struct
180{
181 void (*const build)(uint8_t *work);
182 void (*const soc)(uint8_t *work);
183 void (*const preq)(uint8_t *work);
184 void (*const pres)(uint8_t *work);
185 void (*const soa)(uint8_t *work);
186 void (*const asnd)(uint8_t *work);
187 void (*const parse)(uint8_t *work);
188} PowerlinkNs;
189
190// What the table binds, defined once in the .c and taking one parameter each: everything
191// else an entry needs is an operand in PowerlinkV or a region of the borrow at a fixed offset.
192void protocore_powerlink_build(uint8_t *work);
193void protocore_powerlink_soc(uint8_t *work);
194void protocore_powerlink_preq(uint8_t *work);
195void protocore_powerlink_pres(uint8_t *work);
196void protocore_powerlink_soa(uint8_t *work);
197void protocore_powerlink_asnd(uint8_t *work);
198void protocore_powerlink_parse(uint8_t *work);
199
200// `static const`, initialised HERE rather than `extern` against a definition in the .c: a
201// const object whose initializer every translation unit can see is a COMPILE-TIME FACT, so
202// `Powerlink.build(work)` resolves to a named function and becomes a DIRECT call. An extern table
203// leaves the call indirect and the symbol live at every level, -O2 -flto included.
204static const PowerlinkNs Powerlink __attribute__((unused)) = {
205 .build = protocore_powerlink_build,
206 .soc = protocore_powerlink_soc,
207 .preq = protocore_powerlink_preq,
208 .pres = protocore_powerlink_pres,
209 .soa = protocore_powerlink_soa,
210 .asnd = protocore_powerlink_asnd,
211 .parse = protocore_powerlink_parse,
212};
213
215
216#endif // PROTOCORE_ENABLE_POWERLINK
217
218#endif // PROTOCORE_POWERLINK_H
#define PROTOCORE_BEGIN_DECLS
Give a header's declarations C linkage, so their symbol names carry no parameter types.
Definition types.h:96
_Bool proto_bool
The truth value.
Definition types.h:64
#define PROTOCORE_END_DECLS
Definition types.h:97