ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
wisun.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_WISUN_H
5#define PROTOCORE_WISUN_H
6
7#include "protocore_config.h" // the entry point: protocore_types.h for the widths
8#include "shared/ip/ip.h" // the complete type a public struct below holds by value
9
11
12/**
13 * @file wisun.h
14 * @brief Wi-SUN FAN border-router connector (PROTOCORE_ENABLE_WISUN).
15 *
16 * Wi-SUN FAN is an IPv6 / UDP / CoAP mesh, not a byte-level radio the ESP32 drives - the FAN radio is
17 * terminated by a **border router / devboard** and each mesh node is reached as an ordinary IPv6 CoAP
18 * endpoint. So the connector rides the existing IP stack: it keeps a table of the FAN nodes (their IPv6
19 * `protocore_ip` addresses + join state) behind the border router, and builds the CoAP client requests to their
20 * resources (the CoAP service ships a *server*, so the client-request builder is here). The app sends the
21 * built PDU to the node's address over `protocore_udp`; the specific devboard only sets which border router you
22 * point at, not this code.
23 *
24 * Pure: `protocore_wisun_build_coap` frames an RFC 7252 request (header + Uri-Path options + payload), the node
25 * registry tracks the mesh, and `protocore_wisun_nodes_json` exposes it to the web. No heap, no stdlib,
26 * host-testable.
27 *
28 * @c work is bytes the CALLER holds. This module reads none of them: it carries nothing
29 * between calls, so there is no state to keep and nothing to wipe. The parameter is there so
30 * a caller drives every namespace the same way.
31 */
32
33// PROTOCORE_WISUN_BORROW - the bytes this module runs out of - is stated in protocore_config.h, which sums
34// it into its arena. Its size and its offset are each a static_assert, so a feature
35// combination that does not fit fails to compile rather than overrunning at run time.
36
37/** @brief CoAP message type + method codes (RFC 7252) used by the connector. */
38#define WISUN_COAP_CON 0 ///< Confirmable.
39#define WISUN_COAP_NON 1 ///< Non-confirmable.
40#define WISUN_COAP_GET 1 ///< method code 0.01.
41#define WISUN_COAP_PUT 3 ///< method code 0.03.
42
43/** @brief One FAN mesh node behind the border router. */
44typedef struct
45{
46 protocore_ip addr; ///< the node's IPv6 address on the mesh.
47 proto_bool joined; ///< true once the node has joined the FAN.
48 uint32_t last_seen; ///< tick of the last contact.
49} WisunNode;
50
51/** @brief The FAN connector state over a caller-owned node table. */
52typedef struct
53{
54 protocore_ip border_router; ///< the border router / devboard address.
56 size_t count;
57 size_t cap;
58} WisunFan;
59
60#include "shared/ip/ip.h" // protocore_ip: the type a parameter points at
61
62/** @brief Dispatch table. Addressed by offset, so the layout is asserted below. */
63typedef struct
64{
65 size_t (*build_coap)(uint8_t *, uint8_t, uint8_t, uint16_t, const uint8_t *, uint8_t, const char *, const uint8_t *,
66 size_t, uint8_t *, size_t);
67 void (*init)(uint8_t *, WisunFan *, const protocore_ip *, WisunNode *, size_t);
68 int (*node_register)(uint8_t *, WisunFan *, const protocore_ip *, uint32_t);
69 proto_bool (*node_find)(uint8_t *, const WisunFan *, const protocore_ip *, size_t *);
70 size_t (*joined_count)(uint8_t *, const WisunFan *);
71 size_t (*nodes_json)(uint8_t *, const WisunFan *, char *, size_t);
72} WisunNs;
73PROTOCORE_NS_LAYOUT(WisunNs, build_coap, init, node_register, node_find, joined_count, nodes_json);
74
75/**
76 * @brief Build a CoAP client request: header + Uri-Path options (one per `/` .
77 * @param work PROTOCORE_WISUN_BORROW bytes the caller took. Not held past the call.
78 * @param type WISUN_COAP_CON / WISUN_COAP_NON
79 * @param code method code (WISUN_COAP_GET / WISUN_COAP_PUT)
80 * @param msg_id the 16-bit message id (echoed in the ACK)
81 * @param token correlation token (0..8 bytes; may be null if tkl == 0)
82 * @param tkl token length
83 * @param uri_path resource path, e.g. "sensors/temp" (leading / optional)
84 * @param payload request body (may be null if plen == 0)
85 * @param plen payload length
86 * @param out Out
87 * @param cap Cap
88 * @return The size_t.
89 */
90size_t protocore_wisun_build_coap(uint8_t *work, uint8_t type, uint8_t code, uint16_t msg_id, const uint8_t *token,
91 uint8_t tkl, const char *uri_path, const uint8_t *payload, size_t plen, uint8_t *out,
92 size_t cap);
93/**
94 * @brief Initialize the connector over caller storage.
95 * @param work PROTOCORE_WISUN_BORROW bytes the caller took. Not held past the call.
96 * @param fan Fan
97 * @param border_router Border router
98 * @param storage Storage
99 * @param cap Cap
100 */
101void protocore_wisun_init(uint8_t *work, WisunFan *fan, const protocore_ip *border_router, WisunNode *storage,
102 size_t cap);
103/**
104 * @brief Register (or refresh) a node by address; sets joined + last_seen.
105 * @param work PROTOCORE_WISUN_BORROW bytes the caller took. Not held past the call.
106 * @param fan Fan
107 * @param addr Addr
108 * @param now Now
109 * @return The int.
110 */
111int protocore_wisun_node_register(uint8_t *work, WisunFan *fan, const protocore_ip *addr, uint32_t now);
112/**
113 * @brief Find a node by address. idx (may be null) receives the index. found.
114 * @param work PROTOCORE_WISUN_BORROW bytes the caller took. Not held past the call.
115 * @param fan Fan
116 * @param addr Addr
117 * @param idx Idx
118 * @return PROTO_TRUE on success.
119 */
120proto_bool protocore_wisun_node_find(uint8_t *work, const WisunFan *fan, const protocore_ip *addr, size_t *idx);
121/**
122 * @brief Number of joined nodes.
123 * @param work PROTOCORE_WISUN_BORROW bytes the caller took. Not held past the call.
124 * @param fan Fan
125 * @return The size_t.
126 */
127size_t protocore_wisun_joined_count(uint8_t *work, const WisunFan *fan);
128/**
129 * @brief Serialize the node table as `[{"addr":"..","joined":bool},...]` for .
130 * @param work PROTOCORE_WISUN_BORROW bytes the caller took. Not held past the call.
131 * @param fan Fan
132 * @param out Out
133 * @param cap Cap
134 * @return The size_t.
135 */
136size_t protocore_wisun_nodes_json(uint8_t *work, const WisunFan *fan, char *out, size_t cap);
137
138/** @brief Module namespace. */
145
147
148#endif // PROTOCORE_WISUN_H
Layer 3 (Network) - a family-tagged IP address (IPv4 or IPv6) with RFC-faithful text parsing,...
#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.
The FAN connector state over a caller-owned node table.
Definition wisun.h:53
WisunNode * nodes
Definition wisun.h:55
protocore_ip border_router
the border router / devboard address.
Definition wisun.h:54
size_t cap
Definition wisun.h:57
size_t count
Definition wisun.h:56
One FAN mesh node behind the border router.
Definition wisun.h:45
proto_bool joined
true once the node has joined the FAN.
Definition wisun.h:47
uint32_t last_seen
tick of the last contact.
Definition wisun.h:48
protocore_ip addr
the node's IPv6 address on the mesh.
Definition wisun.h:46
Dispatch table. Addressed by offset, so the layout is asserted below.
Definition wisun.h:64
size_t(* build_coap)(uint8_t *, uint8_t, uint8_t, uint16_t, const uint8_t *, uint8_t, const char *, const uint8_t *, size_t, uint8_t *, size_t)
Definition wisun.h:65
A v4 or v6 address in network (big-endian) byte order.
Definition ip.h:56
#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
proto_bool protocore_wisun_node_find(uint8_t *work, const WisunFan *fan, const protocore_ip *addr, size_t *idx)
Find a node by address. idx (may be null) receives the index. found.
void protocore_wisun_init(uint8_t *work, WisunFan *fan, const protocore_ip *border_router, WisunNode *storage, size_t cap)
Initialize the connector over caller storage.
PROTOCORE_NS WisunNs Wisun PROTOCORE_UNUSED
Module namespace.
Definition wisun.h:139
int protocore_wisun_node_register(uint8_t *work, WisunFan *fan, const protocore_ip *addr, uint32_t now)
Register (or refresh) a node by address; sets joined + last_seen.
size_t protocore_wisun_joined_count(uint8_t *work, const WisunFan *fan)
Number of joined nodes.
size_t protocore_wisun_nodes_json(uint8_t *work, const WisunFan *fan, char *out, size_t cap)
Serialize the node table as [{"addr":"..","joined":bool},...] for .
size_t protocore_wisun_build_coap(uint8_t *work, uint8_t type, uint8_t code, uint16_t msg_id, const uint8_t *token, uint8_t tkl, const char *uri_path, const uint8_t *payload, size_t plen, uint8_t *out, size_t cap)
Build a CoAP client request: header + Uri-Path options (one per / .