ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
thread.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#ifndef PROTOCORE_THREAD_H
5#define PROTOCORE_THREAD_H
6
7#include "protocore_config.h" // the entry point: protocore_types.h for the widths
8
10
11/**
12 * @file thread.h
13 * @brief Thread spinel / HDLC-lite framing codec (PROTOCORE_ENABLE_THREAD) - OpenThread RCP.
14 *
15 * The HDLC-lite framing that carries spinel frames to an OpenThread radio co-processor (an
16 * nRF52840 / EFR32 RCP) over UART - an 802.15.4 / Thread mesh bridged to IP and the web.
17 * HDLC-lite wraps each spinel frame by appending an FCS, byte-stuffing the reserved bytes,
18 * and terminating with a Flag:
19 *
20 * [spinel payload | FCS(lo,hi)] --byte-stuffed--> ... | 0x7E
21 *
22 * The FCS is the HDLC frame check sequence, **CRC-16/X-25** (poly 0x1021 reflected, init
23 * 0xFFFF, reflected in/out, final XOR 0xFFFF), transmitted low byte first. The reserved
24 * bytes stuffed (as 0x7D, byte XOR 0x20) are the Flag 0x7E, the Escape 0x7D, XON 0x11, and
25 * XOFF 0x13.
26 *
27 * protocore_spinel_frame_encode() wraps a payload; protocore_spinel_frame_decode() finds the flag, removes the
28 * stuffing, and verifies the FCS. protocore_spinel_fcs() is the shared checksum. The spinel command
29 * inside (a property get/set/insert, an 802.15.4 stream) is the application's. Pure - you
30 * carry the bytes over your UART - so it is fully host-testable.
31 *
32 * @c work is bytes the CALLER holds. This module reads none of them: it carries nothing
33 * between calls, so there is no state to keep and nothing to wipe. The parameter is there so
34 * a caller drives every namespace the same way.
35 *
36 * @author Douglas Quigg (dstroy0)
37 * @date 2026
38 */
39
40// PROTOCORE_THREAD_BORROW - the bytes this module runs out of - is stated in protocore_config.h, which sums
41// it into its arena. Its size and its offset are each a static_assert, so a feature
42// combination that does not fit fails to compile rather than overrunning at run time.
43
44/** @brief HDLC-lite markers. */
45#define HDLC_FLAG 0x7E ///< frame delimiter
46#define HDLC_ESCAPE 0x7D ///< byte-stuffing escape
47
48/** @brief Common spinel commands (the property accessors a gateway uses). */
49#define SPINEL_CMD_NOOP 0
50#define SPINEL_CMD_RESET 1
51#define SPINEL_CMD_PROP_VALUE_GET 2
52#define SPINEL_CMD_PROP_VALUE_SET 3
53#define SPINEL_CMD_PROP_VALUE_INSERT 4
54#define SPINEL_CMD_PROP_VALUE_REMOVE 5
55#define SPINEL_CMD_PROP_VALUE_IS 6 ///< an async property update from the NCP
56#define SPINEL_CMD_PROP_VALUE_INSERTED 7 ///< a list property gained an entry
57#define SPINEL_CMD_PROP_VALUE_REMOVED 8 ///< a list property lost an entry
58
59/**
60 * @brief The spinel property ids a Thread/802.15.4 gateway reads or writes (subset of the
61 * spinel property registry, grouped CORE / PHY / MAC / NET / IPv6 / STREAM).
62 */
63// Core (SPINEL_PROP_CORE__BEGIN = 0)
64#define SPINEL_PROP_LAST_STATUS 0 ///< 'i' last operation status
65#define SPINEL_PROP_PROTOCOL_VERSION 1 ///< 'ii' major, minor
66#define SPINEL_PROP_NCP_VERSION 2 ///< 'U' NCP version string
67#define SPINEL_PROP_INTERFACE_TYPE 3 ///< 'i' 3 = Thread
68#define SPINEL_PROP_VENDOR_ID 4 ///< 'i'
69#define SPINEL_PROP_CAPS 5 ///< 'A(i)' capability list
70#define SPINEL_PROP_INTERFACE_COUNT 6 ///< 'C'
71#define SPINEL_PROP_HWADDR 8 ///< 'E' factory EUI64
72#define SPINEL_PROP_LOCK 9 ///< 'b'
73
74// PHY (SPINEL_PROP_PHY__BEGIN = 0x20)
75#define SPINEL_PROP_PHY_ENABLED 0x20 ///< 'b'
76#define SPINEL_PROP_PHY_CHAN 0x21 ///< 'C' 802.15.4 channel
77#define SPINEL_PROP_PHY_CHAN_SUPPORTED 0x22 ///< 'A(C)'
78#define SPINEL_PROP_PHY_FREQ 0x23 ///< 'L' kHz
79#define SPINEL_PROP_PHY_TX_POWER 0x25 ///< 'c' dBm
80#define SPINEL_PROP_PHY_RSSI 0x26 ///< 'c' dBm
81
82// MAC (SPINEL_PROP_MAC__BEGIN = 0x30)
83#define SPINEL_PROP_MAC_SCAN_STATE 0x30 ///< 'C'
84#define SPINEL_PROP_MAC_SCAN_MASK 0x31 ///< 'A(C)'
85#define SPINEL_PROP_MAC_SCAN_PERIOD 0x32 ///< 'S' ms/channel
86#define SPINEL_PROP_MAC_15_4_LADDR 0x34 ///< 'E' extended (long) address
87#define SPINEL_PROP_MAC_15_4_SADDR 0x35 ///< 'S' short address
88#define SPINEL_PROP_MAC_15_4_PANID 0x36 ///< 'S' PAN id
89
90// NET (SPINEL_PROP_NET__BEGIN = 0x40)
91#define SPINEL_PROP_NET_SAVED 0x40 ///< 'b'
92#define SPINEL_PROP_NET_IF_UP 0x41 ///< 'b'
93#define SPINEL_PROP_NET_STACK_UP 0x42 ///< 'b'
94#define SPINEL_PROP_NET_ROLE 0x43 ///< 'C' 0 detached,1 child,2 router,3 leader
95#define SPINEL_PROP_NET_NETWORK_NAME 0x44 ///< 'U'
96#define SPINEL_PROP_NET_XPANID 0x45 ///< 'D' 8-byte extended PAN id
97#define SPINEL_PROP_NET_NETWORK_KEY 0x46 ///< 'D' 16-byte network key
98
99// IPv6 (SPINEL_PROP_IPV6__BEGIN = 0x60)
100#define SPINEL_PROP_IPV6_LL_ADDR 0x60 ///< '6' link-local
101#define SPINEL_PROP_IPV6_ML_ADDR 0x61 ///< '6' mesh-local
102
103// Stream (SPINEL_PROP_STREAM__BEGIN = 0x70)
104#define SPINEL_PROP_STREAM_DEBUG 0x70 ///< 'U' debug text
105#define SPINEL_PROP_STREAM_RAW 0x71 ///< 'dD' raw 802.15.4 frame + metadata
106#define SPINEL_PROP_STREAM_NET 0x72 ///< 'dD' IPv6 datagram + metadata
107
108/** @brief spinel `LAST_STATUS` codes (a subset - the ones a gateway acts on). */
109#define SPINEL_STATUS_OK 0
110#define SPINEL_STATUS_FAILURE 1
111#define SPINEL_STATUS_UNIMPLEMENTED 2
112#define SPINEL_STATUS_INVALID_ARGUMENT 3
113#define SPINEL_STATUS_INVALID_STATE 4
114#define SPINEL_STATUS_INVALID_COMMAND 5
115#define SPINEL_STATUS_INVALID_INTERFACE 6
116#define SPINEL_STATUS_INTERNAL_ERROR 7
117#define SPINEL_STATUS_SECURITY_ERROR 8
118#define SPINEL_STATUS_PARSE_ERROR 9
119#define SPINEL_STATUS_IN_PROGRESS 10
120#define SPINEL_STATUS_NOMEM 11
121#define SPINEL_STATUS_BUSY 12
122#define SPINEL_STATUS_PROP_NOT_FOUND 13
123#define SPINEL_STATUS_DROPPED 14
124#define SPINEL_STATUS_EMPTY 15
125#define SPINEL_STATUS_RESET_POWER_ON 112 ///< first of the reset-cause block
126#define SPINEL_STATUS_RESET_END 128 ///< one past the block: 112..127 are all reset causes
127
128/** @brief A read cursor over a spinel property value. */
129typedef struct
130{
131 const uint8_t *buf; ///< the value bytes
132 uint16_t len; ///< value length
133 uint16_t off; ///< next unread offset
134 proto_bool err; ///< set once any read runs past the end / is malformed
136
137/** @brief A write cursor building a spinel property value into a caller buffer. */
138typedef struct
139{
140 uint8_t *buf; ///< output buffer
141 uint16_t cap; ///< output capacity
142 uint16_t off; ///< bytes written so far
143 proto_bool err; ///< set once any write would overflow @c cap
145
146/** @brief A registry entry: a property id, its human name, and its primary spinel datatype char. */
147typedef struct
148{
149 uint32_t id;
150 const char *name;
151 char type; ///< the leading spinel datatype ('U','i','C','c','S','E','6','b','D', or '.')
153
154/** @brief Build a spinel header byte for interface @p iid and transaction @p tid (tid 0 = no response wanted). */
155static inline uint8_t protocore_spinel_header(uint8_t iid, uint8_t tid)
156{
157 return (uint8_t)(0x80 | ((iid & 0x03) << 4) | (tid & 0x0F));
158}
159
160/** @brief The transaction id carried in header byte @p h. */
161static inline uint8_t protocore_spinel_header_tid(uint8_t h)
162{
163 return (uint8_t)(h & 0x0F);
164}
165
166/** @brief The interface id carried in header byte @p h. */
167static inline uint8_t protocore_spinel_header_iid(uint8_t h)
168{
169 return (uint8_t)((h >> 4) & 0x03);
170}
171
172/** @brief Dispatch table. Addressed by offset, so the layout is asserted below. */
173typedef struct
174{
175 uint16_t (*spinel_fcs)(uint8_t *, const uint8_t *, uint16_t);
176 uint8_t (*spinel_pack_uint)(uint8_t *, uint32_t, uint8_t *, uint8_t);
177 int (*spinel_unpack_uint)(uint8_t *, const uint8_t *, uint8_t, uint32_t *);
178 uint16_t (*spinel_command_build)(uint8_t *, uint8_t, uint32_t, uint32_t, const uint8_t *, uint16_t, uint8_t *,
179 uint16_t);
180 int (*spinel_command_parse)(uint8_t *, const uint8_t *, uint16_t, uint8_t *, uint32_t *, uint32_t *,
181 const uint8_t **, uint16_t *);
182 void (*spinel_reader_init)(uint8_t *, SpinelReader *, const uint8_t *, uint16_t);
183 proto_bool (*spinel_get_bool)(uint8_t *, SpinelReader *, proto_bool *);
184 proto_bool (*spinel_get_u8)(uint8_t *, SpinelReader *, uint8_t *);
185 proto_bool (*spinel_get_i8)(uint8_t *, SpinelReader *, int8_t *);
186 proto_bool (*spinel_get_u16)(uint8_t *, SpinelReader *, uint16_t *);
187 proto_bool (*spinel_get_i16)(uint8_t *, SpinelReader *, int16_t *);
188 proto_bool (*spinel_get_u32)(uint8_t *, SpinelReader *, uint32_t *);
189 proto_bool (*spinel_get_i32)(uint8_t *, SpinelReader *, int32_t *);
190 proto_bool (*spinel_get_uint)(uint8_t *, SpinelReader *, uint32_t *);
191 proto_bool (*spinel_get_eui64)(uint8_t *, SpinelReader *, const uint8_t **);
192 proto_bool (*spinel_get_ipv6)(uint8_t *, SpinelReader *, const uint8_t **);
193 proto_bool (*spinel_get_utf8)(uint8_t *, SpinelReader *, const char **, uint16_t *);
194 proto_bool (*spinel_get_data)(uint8_t *, SpinelReader *, const uint8_t **, uint16_t *);
195 proto_bool (*spinel_get_data_wlen)(uint8_t *, SpinelReader *, const uint8_t **, uint16_t *);
196 proto_bool (*spinel_reader_ok)(uint8_t *, const SpinelReader *);
197 void (*spinel_writer_init)(uint8_t *, SpinelWriter *, uint8_t *, uint16_t);
198 proto_bool (*spinel_put_bool)(uint8_t *, SpinelWriter *, proto_bool);
199 proto_bool (*spinel_put_u8)(uint8_t *, SpinelWriter *, uint8_t);
200 void (*spinel_put_i8)(uint8_t *, SpinelWriter *, int8_t);
201 proto_bool (*spinel_put_u16)(uint8_t *, SpinelWriter *, uint16_t);
202 void (*spinel_put_i16)(uint8_t *, SpinelWriter *, int16_t);
203 proto_bool (*spinel_put_u32)(uint8_t *, SpinelWriter *, uint32_t);
204 void (*spinel_put_i32)(uint8_t *, SpinelWriter *, int32_t);
205 proto_bool (*spinel_put_uint)(uint8_t *, SpinelWriter *, uint32_t);
206 proto_bool (*spinel_put_eui64)(uint8_t *, SpinelWriter *, const uint8_t *);
207 proto_bool (*spinel_put_ipv6)(uint8_t *, SpinelWriter *, const uint8_t *);
208 proto_bool (*spinel_put_utf8)(uint8_t *, SpinelWriter *, const char *);
209 proto_bool (*spinel_put_data)(uint8_t *, SpinelWriter *, const uint8_t *, uint16_t);
210 proto_bool (*spinel_put_data_wlen)(uint8_t *, SpinelWriter *, const uint8_t *, uint16_t);
211 uint16_t (*spinel_writer_len)(uint8_t *, const SpinelWriter *);
212 const SpinelPropInfo *(*spinel_prop_lookup)(uint8_t *, uint32_t);
213 const char *(*spinel_prop_name)(uint8_t *, uint32_t);
214 const char *(*spinel_status_name)(uint8_t *, uint32_t);
215 uint16_t (*spinel_frame_encode)(uint8_t *, const uint8_t *, uint16_t, uint8_t *, uint16_t);
216 int (*spinel_frame_decode)(uint8_t *, const uint8_t *, uint16_t, uint8_t *, uint16_t, uint16_t *);
217} ThreadNs;
218PROTOCORE_NS_LAYOUT(ThreadNs, spinel_fcs, spinel_pack_uint, spinel_unpack_uint, spinel_command_build,
219 spinel_command_parse, spinel_reader_init, spinel_get_bool, spinel_get_u8, spinel_get_i8,
220 spinel_get_u16, spinel_get_i16, spinel_get_u32, spinel_get_i32, spinel_get_uint, spinel_get_eui64,
221 spinel_get_ipv6, spinel_get_utf8, spinel_get_data, spinel_get_data_wlen, spinel_reader_ok,
222 spinel_writer_init, spinel_put_bool, spinel_put_u8, spinel_put_i8, spinel_put_u16, spinel_put_i16,
223 spinel_put_u32, spinel_put_i32, spinel_put_uint, spinel_put_eui64, spinel_put_ipv6, spinel_put_utf8,
224 spinel_put_data, spinel_put_data_wlen, spinel_writer_len, spinel_prop_lookup, spinel_prop_name,
225 spinel_status_name, spinel_frame_encode, spinel_frame_decode);
226
227/**
228 * @brief HDLC frame check sequence: CRC-16/X-25 over buf.
229 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
230 * @param buf Buf
231 * @param len Len
232 * @return The uint16_t.
233 */
234uint16_t protocore_thread_spinel_fcs(uint8_t *work, const uint8_t *buf, uint16_t len);
235/**
236 * @brief Encode a spinel packed unsigned integer (7 bits/byte, .
237 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
238 * @param value Value
239 * @param out Out
240 * @param cap Cap
241 * @return The uint8_t.
242 */
243uint8_t protocore_thread_spinel_pack_uint(uint8_t *work, uint32_t value, uint8_t *out, uint8_t cap);
244/**
245 * @brief Decode a spinel packed unsigned integer from the front of raw.
246 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
247 * @param raw Raw
248 * @param len Len
249 * @param value Value
250 * @return The int.
251 */
252int protocore_thread_spinel_unpack_uint(uint8_t *work, const uint8_t *raw, uint8_t len, uint32_t *value);
253/**
254 * @brief Build a spinel property-command payload (`header | CMD | PROP | .
255 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
256 * @param header Header
257 * @param cmd Cmd
258 * @param prop Prop
259 * @param value Value
260 * @param value_len Value len
261 * @param out Out
262 * @param cap Cap
263 * @return The uint16_t.
264 */
265uint16_t protocore_thread_spinel_command_build(uint8_t *work, uint8_t header, uint32_t cmd, uint32_t prop,
266 const uint8_t *value, uint16_t value_len, uint8_t *out, uint16_t cap);
267/**
268 * @brief Parse a spinel property-command payload (from a decoded HDLC frame).
269 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
270 * @param payload Payload
271 * @param len Len
272 * @param header Header
273 * @param cmd Cmd
274 * @param prop Prop
275 * @param value Value
276 * @param value_len Value len
277 * @return The int.
278 */
279int protocore_thread_spinel_command_parse(uint8_t *work, const uint8_t *payload, uint16_t len, uint8_t *header,
280 uint32_t *cmd, uint32_t *prop, const uint8_t **value, uint16_t *value_len);
281/**
282 * @brief Spinel_reader_init.
283 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
284 * @param r R
285 * @param value Value
286 * @param len Len
287 */
288void protocore_thread_spinel_reader_init(uint8_t *work, SpinelReader *r, const uint8_t *value, uint16_t len);
289/**
290 * @brief Spinel_get_bool.
291 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
292 * @param r R
293 * @param out Out
294 * @return PROTO_TRUE on success.
295 */
297/**
298 * @brief Spinel_get_u8.
299 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
300 * @param r R
301 * @param out Out
302 * @return PROTO_TRUE on success.
303 */
305/**
306 * @brief Spinel_get_i8.
307 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
308 * @param r R
309 * @param out Out
310 * @return PROTO_TRUE on success.
311 */
313/**
314 * @brief Spinel_get_u16.
315 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
316 * @param r R
317 * @param out Out
318 * @return PROTO_TRUE on success.
319 */
321/**
322 * @brief Spinel_get_i16.
323 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
324 * @param r R
325 * @param out Out
326 * @return PROTO_TRUE on success.
327 */
329/**
330 * @brief Spinel_get_u32.
331 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
332 * @param r R
333 * @param out Out
334 * @return PROTO_TRUE on success.
335 */
337/**
338 * @brief Spinel_get_i32.
339 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
340 * @param r R
341 * @param out Out
342 * @return PROTO_TRUE on success.
343 */
345/**
346 * @brief Spinel_get_uint.
347 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
348 * @param r R
349 * @param out Out
350 * @return PROTO_TRUE on success.
351 */
353/**
354 * @brief Spinel_get_eui64.
355 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
356 * @param r R
357 * @param out8 Out8
358 * @return PROTO_TRUE on success.
359 */
360proto_bool protocore_thread_spinel_get_eui64(uint8_t *work, SpinelReader *r, const uint8_t **out8);
361/**
362 * @brief Spinel_get_ipv6.
363 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
364 * @param r R
365 * @param out16 Out16
366 * @return PROTO_TRUE on success.
367 */
368proto_bool protocore_thread_spinel_get_ipv6(uint8_t *work, SpinelReader *r, const uint8_t **out16);
369/**
370 * @brief UTF8 'U': out points into the value, out_len excludes the NUL; .
371 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
372 * @param r R
373 * @param out Out
374 * @param out_len Out len
375 * @return PROTO_TRUE on success.
376 */
377proto_bool protocore_thread_spinel_get_utf8(uint8_t *work, SpinelReader *r, const char **out, uint16_t *out_len);
378/**
379 * @brief Data 'D' (to end of value): out points into the value, out_len is .
380 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
381 * @param r R
382 * @param out Out
383 * @param out_len Out len
384 * @return PROTO_TRUE on success.
385 */
386proto_bool protocore_thread_spinel_get_data(uint8_t *work, SpinelReader *r, const uint8_t **out, uint16_t *out_len);
387/**
388 * @brief Data 'd' (uint16-LE length prefix): reads the count, then that many .
389 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
390 * @param r R
391 * @param out Out
392 * @param out_len Out len
393 * @return PROTO_TRUE on success.
394 */
395proto_bool protocore_thread_spinel_get_data_wlen(uint8_t *work, SpinelReader *r, const uint8_t **out,
396 uint16_t *out_len);
397/**
398 * @brief True if every read so far stayed in bounds.
399 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
400 * @param r R
401 * @return PROTO_TRUE on success.
402 */
404/**
405 * @brief Spinel_writer_init.
406 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
407 * @param w W
408 * @param out Out
409 * @param cap Cap
410 */
411void protocore_thread_spinel_writer_init(uint8_t *work, SpinelWriter *w, uint8_t *out, uint16_t cap);
412/**
413 * @brief Spinel_put_bool.
414 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
415 * @param w W
416 * @param v V
417 * @return PROTO_TRUE on success.
418 */
420/**
421 * @brief Spinel_put_u8.
422 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
423 * @param w W
424 * @param v V
425 * @return PROTO_TRUE on success.
426 */
428/**
429 * @brief Spinel_put_i8.
430 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
431 * @param w W
432 * @param v V
433 */
434void protocore_thread_spinel_put_i8(uint8_t *work, SpinelWriter *w, int8_t v);
435/**
436 * @brief Spinel_put_u16.
437 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
438 * @param w W
439 * @param v V
440 * @return PROTO_TRUE on success.
441 */
443/**
444 * @brief Spinel_put_i16.
445 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
446 * @param w W
447 * @param v V
448 */
449void protocore_thread_spinel_put_i16(uint8_t *work, SpinelWriter *w, int16_t v);
450/**
451 * @brief Spinel_put_u32.
452 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
453 * @param w W
454 * @param v V
455 * @return PROTO_TRUE on success.
456 */
458/**
459 * @brief Spinel_put_i32.
460 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
461 * @param w W
462 * @param v V
463 */
464void protocore_thread_spinel_put_i32(uint8_t *work, SpinelWriter *w, int32_t v);
465/**
466 * @brief Spinel_put_uint.
467 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
468 * @param w W
469 * @param v V
470 * @return PROTO_TRUE on success.
471 */
473/**
474 * @brief Spinel_put_eui64.
475 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
476 * @param w W
477 * @param v8 V8
478 * @return PROTO_TRUE on success.
479 */
480proto_bool protocore_thread_spinel_put_eui64(uint8_t *work, SpinelWriter *w, const uint8_t *v8);
481/**
482 * @brief Spinel_put_ipv6.
483 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
484 * @param w W
485 * @param v16 V16
486 * @return PROTO_TRUE on success.
487 */
488proto_bool protocore_thread_spinel_put_ipv6(uint8_t *work, SpinelWriter *w, const uint8_t *v16);
489/**
490 * @brief Spinel_put_utf8.
491 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
492 * @param w W
493 * @param s S
494 * @return PROTO_TRUE on success.
495 */
497/**
498 * @brief Spinel_put_data.
499 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
500 * @param w W
501 * @param d D
502 * @param n N
503 * @return PROTO_TRUE on success.
504 */
505proto_bool protocore_thread_spinel_put_data(uint8_t *work, SpinelWriter *w, const uint8_t *d, uint16_t n);
506/**
507 * @brief Spinel_put_data_wlen.
508 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
509 * @param w W
510 * @param d D
511 * @param n N
512 * @return PROTO_TRUE on success.
513 */
514proto_bool protocore_thread_spinel_put_data_wlen(uint8_t *work, SpinelWriter *w, const uint8_t *d, uint16_t n);
515/**
516 * @brief The finished value length, or 0 if any write overflowed.
517 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
518 * @param w W
519 * @return The uint16_t.
520 */
521uint16_t protocore_thread_spinel_writer_len(uint8_t *work, const SpinelWriter *w);
522/**
523 * @brief Look up a property's registry entry, or nullptr if it is not in the .
524 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
525 * @param id Id
526 * @return The const SpinelPropInfo *.
527 */
528const SpinelPropInfo *protocore_thread_spinel_prop_lookup(uint8_t *work, uint32_t id);
529/**
530 * @brief A property's human name, or "UNKNOWN" if unregistered.
531 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
532 * @param id Id
533 * @return The const char *.
534 */
535const char *protocore_thread_spinel_prop_name(uint8_t *work, uint32_t id);
536/**
537 * @brief A `LAST_STATUS` code's human name, or "UNKNOWN" if unregistered.
538 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
539 * @param status Status
540 * @return The const char *.
541 */
542const char *protocore_thread_spinel_status_name(uint8_t *work, uint32_t status);
543/**
544 * @brief Encode an HDLC-lite frame: payload + FCS, byte-stuffed, .
545 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
546 * @param payload Payload
547 * @param len Len
548 * @param out Out
549 * @param cap Cap
550 * @return The uint16_t.
551 */
552uint16_t protocore_thread_spinel_frame_encode(uint8_t *work, const uint8_t *payload, uint16_t len, uint8_t *out,
553 uint16_t cap);
554/**
555 * @brief Decode one HDLC-lite frame from the front of raw: find the flag, .
556 * @param work PROTOCORE_THREAD_BORROW bytes the caller took. Not held past the call.
557 * @param raw Raw
558 * @param len Len
559 * @param payload Payload
560 * @param pay_cap Pay cap
561 * @param pay_len Pay len
562 * @return The int.
563 */
564int protocore_thread_spinel_frame_decode(uint8_t *work, const uint8_t *raw, uint16_t len, uint8_t *payload,
565 uint16_t pay_cap, uint16_t *pay_len);
566
567/** @brief Module namespace. */
569 .spinel_pack_uint = protocore_thread_spinel_pack_uint,
570 .spinel_unpack_uint = protocore_thread_spinel_unpack_uint,
571 .spinel_command_build = protocore_thread_spinel_command_build,
572 .spinel_command_parse = protocore_thread_spinel_command_parse,
573 .spinel_reader_init = protocore_thread_spinel_reader_init,
574 .spinel_get_bool = protocore_thread_spinel_get_bool,
575 .spinel_get_u8 = protocore_thread_spinel_get_u8,
576 .spinel_get_i8 = protocore_thread_spinel_get_i8,
577 .spinel_get_u16 = protocore_thread_spinel_get_u16,
578 .spinel_get_i16 = protocore_thread_spinel_get_i16,
579 .spinel_get_u32 = protocore_thread_spinel_get_u32,
580 .spinel_get_i32 = protocore_thread_spinel_get_i32,
581 .spinel_get_uint = protocore_thread_spinel_get_uint,
582 .spinel_get_eui64 = protocore_thread_spinel_get_eui64,
583 .spinel_get_ipv6 = protocore_thread_spinel_get_ipv6,
584 .spinel_get_utf8 = protocore_thread_spinel_get_utf8,
585 .spinel_get_data = protocore_thread_spinel_get_data,
586 .spinel_get_data_wlen = protocore_thread_spinel_get_data_wlen,
587 .spinel_reader_ok = protocore_thread_spinel_reader_ok,
588 .spinel_writer_init = protocore_thread_spinel_writer_init,
589 .spinel_put_bool = protocore_thread_spinel_put_bool,
590 .spinel_put_u8 = protocore_thread_spinel_put_u8,
591 .spinel_put_i8 = protocore_thread_spinel_put_i8,
592 .spinel_put_u16 = protocore_thread_spinel_put_u16,
593 .spinel_put_i16 = protocore_thread_spinel_put_i16,
594 .spinel_put_u32 = protocore_thread_spinel_put_u32,
595 .spinel_put_i32 = protocore_thread_spinel_put_i32,
596 .spinel_put_uint = protocore_thread_spinel_put_uint,
597 .spinel_put_eui64 = protocore_thread_spinel_put_eui64,
598 .spinel_put_ipv6 = protocore_thread_spinel_put_ipv6,
599 .spinel_put_utf8 = protocore_thread_spinel_put_utf8,
600 .spinel_put_data = protocore_thread_spinel_put_data,
601 .spinel_put_data_wlen = protocore_thread_spinel_put_data_wlen,
602 .spinel_writer_len = protocore_thread_spinel_writer_len,
603 .spinel_prop_lookup = protocore_thread_spinel_prop_lookup,
604 .spinel_prop_name = protocore_thread_spinel_prop_name,
605 .spinel_status_name = protocore_thread_spinel_status_name,
606 .spinel_frame_encode = protocore_thread_spinel_frame_encode,
607 .spinel_frame_decode = protocore_thread_spinel_frame_decode};
608
610
611#endif // PROTOCORE_THREAD_H
#define PROTOCORE_NS_LAYOUT(T,...)
Pin every dispatch slot of a table that is nothing but function pointers.
#define PROTOCORE_NS
Storage for a dispatch table. The const is load bearing.
A registry entry: a property id, its human name, and its primary spinel datatype char.
Definition thread.h:148
const char * name
Definition thread.h:150
char type
the leading spinel datatype ('U','i','C','c','S','E','6','b','D', or '.')
Definition thread.h:151
uint32_t id
Definition thread.h:149
A read cursor over a spinel property value.
Definition thread.h:130
uint16_t len
value length
Definition thread.h:132
proto_bool err
set once any read runs past the end / is malformed
Definition thread.h:134
uint16_t off
next unread offset
Definition thread.h:133
const uint8_t * buf
the value bytes
Definition thread.h:131
A write cursor building a spinel property value into a caller buffer.
Definition thread.h:139
proto_bool err
set once any write would overflow cap
Definition thread.h:143
uint16_t off
bytes written so far
Definition thread.h:142
uint16_t cap
output capacity
Definition thread.h:141
uint8_t * buf
output buffer
Definition thread.h:140
Dispatch table. Addressed by offset, so the layout is asserted below.
Definition thread.h:174
uint16_t(* spinel_fcs)(uint8_t *, const uint8_t *, uint16_t)
Definition thread.h:175
void protocore_thread_spinel_writer_init(uint8_t *work, SpinelWriter *w, uint8_t *out, uint16_t cap)
Spinel_writer_init.
proto_bool protocore_thread_spinel_put_u16(uint8_t *work, SpinelWriter *w, uint16_t v)
Spinel_put_u16.
proto_bool protocore_thread_spinel_get_u8(uint8_t *work, SpinelReader *r, uint8_t *out)
Spinel_get_u8.
proto_bool protocore_thread_spinel_get_utf8(uint8_t *work, SpinelReader *r, const char **out, uint16_t *out_len)
UTF8 'U': out points into the value, out_len excludes the NUL; .
proto_bool protocore_thread_spinel_get_data_wlen(uint8_t *work, SpinelReader *r, const uint8_t **out, uint16_t *out_len)
Data 'd' (uint16-LE length prefix): reads the count, then that many .
PROTOCORE_NS ThreadNs Thread PROTOCORE_UNUSED
Module namespace.
Definition thread.h:568
proto_bool protocore_thread_spinel_put_uint(uint8_t *work, SpinelWriter *w, uint32_t v)
Spinel_put_uint.
const SpinelPropInfo * protocore_thread_spinel_prop_lookup(uint8_t *work, uint32_t id)
Look up a property's registry entry, or nullptr if it is not in the .
proto_bool protocore_thread_spinel_get_i16(uint8_t *work, SpinelReader *r, int16_t *out)
Spinel_get_i16.
const char * protocore_thread_spinel_status_name(uint8_t *work, uint32_t status)
A LAST_STATUS code's human name, or "UNKNOWN" if unregistered.
proto_bool protocore_thread_spinel_put_u32(uint8_t *work, SpinelWriter *w, uint32_t v)
Spinel_put_u32.
void protocore_thread_spinel_put_i8(uint8_t *work, SpinelWriter *w, int8_t v)
Spinel_put_i8.
uint8_t protocore_thread_spinel_pack_uint(uint8_t *work, uint32_t value, uint8_t *out, uint8_t cap)
Encode a spinel packed unsigned integer (7 bits/byte, .
void protocore_thread_spinel_put_i16(uint8_t *work, SpinelWriter *w, int16_t v)
Spinel_put_i16.
const char * protocore_thread_spinel_prop_name(uint8_t *work, uint32_t id)
A property's human name, or "UNKNOWN" if unregistered.
uint16_t protocore_thread_spinel_command_build(uint8_t *work, uint8_t header, uint32_t cmd, uint32_t prop, const uint8_t *value, uint16_t value_len, uint8_t *out, uint16_t cap)
Build a spinel property-command payload (`header | CMD | PROP | .
proto_bool protocore_thread_spinel_get_i8(uint8_t *work, SpinelReader *r, int8_t *out)
Spinel_get_i8.
int protocore_thread_spinel_command_parse(uint8_t *work, const uint8_t *payload, uint16_t len, uint8_t *header, uint32_t *cmd, uint32_t *prop, const uint8_t **value, uint16_t *value_len)
Parse a spinel property-command payload (from a decoded HDLC frame).
proto_bool protocore_thread_spinel_put_eui64(uint8_t *work, SpinelWriter *w, const uint8_t *v8)
Spinel_put_eui64.
proto_bool protocore_thread_spinel_put_ipv6(uint8_t *work, SpinelWriter *w, const uint8_t *v16)
Spinel_put_ipv6.
proto_bool protocore_thread_spinel_put_u8(uint8_t *work, SpinelWriter *w, uint8_t v)
Spinel_put_u8.
proto_bool protocore_thread_spinel_get_i32(uint8_t *work, SpinelReader *r, int32_t *out)
Spinel_get_i32.
proto_bool protocore_thread_spinel_put_data_wlen(uint8_t *work, SpinelWriter *w, const uint8_t *d, uint16_t n)
Spinel_put_data_wlen.
int protocore_thread_spinel_unpack_uint(uint8_t *work, const uint8_t *raw, uint8_t len, uint32_t *value)
Decode a spinel packed unsigned integer from the front of raw.
proto_bool protocore_thread_spinel_get_data(uint8_t *work, SpinelReader *r, const uint8_t **out, uint16_t *out_len)
Data 'D' (to end of value): out points into the value, out_len is .
uint16_t protocore_thread_spinel_frame_encode(uint8_t *work, const uint8_t *payload, uint16_t len, uint8_t *out, uint16_t cap)
Encode an HDLC-lite frame: payload + FCS, byte-stuffed, .
proto_bool protocore_thread_spinel_get_bool(uint8_t *work, SpinelReader *r, proto_bool *out)
Spinel_get_bool.
proto_bool protocore_thread_spinel_get_uint(uint8_t *work, SpinelReader *r, uint32_t *out)
Spinel_get_uint.
proto_bool protocore_thread_spinel_get_eui64(uint8_t *work, SpinelReader *r, const uint8_t **out8)
Spinel_get_eui64.
int protocore_thread_spinel_frame_decode(uint8_t *work, const uint8_t *raw, uint16_t len, uint8_t *payload, uint16_t pay_cap, uint16_t *pay_len)
Decode one HDLC-lite frame from the front of raw: find the flag, .
proto_bool protocore_thread_spinel_put_data(uint8_t *work, SpinelWriter *w, const uint8_t *d, uint16_t n)
Spinel_put_data.
proto_bool protocore_thread_spinel_put_utf8(uint8_t *work, SpinelWriter *w, const char *s)
Spinel_put_utf8.
void protocore_thread_spinel_reader_init(uint8_t *work, SpinelReader *r, const uint8_t *value, uint16_t len)
Spinel_reader_init.
uint16_t protocore_thread_spinel_fcs(uint8_t *work, const uint8_t *buf, uint16_t len)
HDLC frame check sequence: CRC-16/X-25 over buf.
proto_bool protocore_thread_spinel_get_u16(uint8_t *work, SpinelReader *r, uint16_t *out)
Spinel_get_u16.
proto_bool protocore_thread_spinel_reader_ok(uint8_t *work, const SpinelReader *r)
True if every read so far stayed in bounds.
uint16_t protocore_thread_spinel_writer_len(uint8_t *work, const SpinelWriter *w)
The finished value length, or 0 if any write overflowed.
void protocore_thread_spinel_put_i32(uint8_t *work, SpinelWriter *w, int32_t v)
Spinel_put_i32.
proto_bool protocore_thread_spinel_put_bool(uint8_t *work, SpinelWriter *w, proto_bool v)
Spinel_put_bool.
proto_bool protocore_thread_spinel_get_u32(uint8_t *work, SpinelReader *r, uint32_t *out)
Spinel_get_u32.
proto_bool protocore_thread_spinel_get_ipv6(uint8_t *work, SpinelReader *r, const uint8_t **out16)
Spinel_get_ipv6.
#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