ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
enocean.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_ENOCEAN_H
5#define PROTOCORE_ENOCEAN_H
6
7#include "protocore_config.h" // the entry point: protocore_types.h for the widths
8
10
11/**
12 * @file enocean.h
13 * @brief EnOcean ESP3 serial codec (PROTOCORE_ENABLE_ENOCEAN) - energy-harvesting 868 MHz.
14 *
15 * A UART telegram codec for EnOcean Serial Protocol 3 (ESP3), the framing every USB /
16 * serial EnOcean gateway (TCM 310 / USB 300) speaks. A telegram is:
17 *
18 * 0x55 | data-len (2, big-endian) | opt-len (1) | packet-type (1) | CRC8H
19 * | data[data-len] | opt[opt-len] | CRC8D
20 *
21 * where CRC8H protects the 4 header bytes and CRC8D protects the data + optional data (both
22 * CRC-8, polynomial 0x07, init 0). protocore_esp3_parse() frames one telegram out of a byte stream,
23 * resynchronizing on a bad sync / CRC, and protocore_esp3_build() assembles one. This is the radio-
24 * plugin codec for the gateway: an inbound RADIO_ERP1 telegram carries a sender id (its
25 * source address) and payload; bridge it northbound with protocore_gateway_uplink(). Pure - you feed
26 * it the UART bytes - so it is fully host-testable. See example EnOceanGateway.
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 * @author Douglas Quigg (dstroy0)
33 * @date 2026
34 */
35
36// PROTOCORE_ENOCEAN_BORROW - the bytes this module runs out of - is stated in protocore_config.h, which sums
37// it into its arena. Its size and its offset are each a static_assert, so a feature
38// combination that does not fit fails to compile rather than overrunning at run time.
39
40/** @brief ESP3 sync byte that starts every telegram. */
41#define ESP3_SYNC 0x55
42
43// Common RORG (telegram-type) codes.
44#define PROTOCORE_ERP_RORG_RPS 0xF6 ///< Repeated Switch communication (rocker switches): 1 payload octet
45#define PROTOCORE_ERP_RORG_1BS 0xD5 ///< 1-byte communication (contacts): 1 payload octet
46#define PROTOCORE_ERP_RORG_4BS 0xA5 ///< 4-byte communication (sensors): 4 payload octets
47#define PROTOCORE_ERP_RORG_VLD 0xD2 ///< Variable-Length Data
48#define PROTOCORE_ERP_RORG_MSC 0xD1 ///< Manufacturer-Specific Communication
49#define PROTOCORE_ERP_RORG_ADT 0xA6 ///< Addressing Destination Telegram
50#define PROTOCORE_ERP_RORG_UTE 0xD4 ///< Universal Teach-in
51
52/** @brief ESP3 packet types (the common ones). */
64
65/** @brief A parsed ESP3 telegram (pointers alias the caller's buffer). */
66typedef struct
67{
68 const uint8_t *data; ///< data field
69 const uint8_t *opt; ///< optional-data field
70 uint16_t data_len; ///< data length
71 uint8_t opt_len; ///< optional-data length
72 protocore_esp3_type type; ///< packet type (protocore_esp3_type)
74
75/** @brief A decoded ERP1 radio telegram (the payload aliases the caller's buffer). */
76typedef struct
77{
78 uint8_t rorg; ///< telegram type (PROTOCORE_ERP_RORG_*)
79 const uint8_t *payload; ///< RORG-specific data, or nullptr if none
80 uint8_t payload_len; ///< payload octets (data length - 6)
81 uint32_t sender_id; ///< 4-octet sender id (big-endian)
82 uint8_t status; ///< status octet (repeater count + telegram-type bits)
84
85/** @brief Dispatch table. Addressed by offset, so the layout is asserted below. */
86typedef struct
87{
88 uint8_t (*esp3_crc8)(uint8_t *, const uint8_t *, uint16_t);
89 int (*esp3_parse)(uint8_t *, const uint8_t *, uint16_t, protocore_esp3_packet *);
90 uint16_t (*esp3_build)(uint8_t *, protocore_esp3_type, const uint8_t *, uint16_t, const uint8_t *, uint8_t,
91 uint8_t *, uint16_t);
92 proto_bool (*erp1_parse)(uint8_t *, const uint8_t *, uint16_t, protocore_erp1 *);
93 uint16_t (*erp1_build)(uint8_t *, uint8_t *, uint16_t, uint8_t, const uint8_t *, uint8_t, uint32_t, uint8_t);
94} EnoceanNs;
95PROTOCORE_NS_LAYOUT(EnoceanNs, esp3_crc8, esp3_parse, esp3_build, erp1_parse, erp1_build);
96
97/**
98 * @brief CRC-8 used by ESP3 (polynomial 0x07, MSB-first, init 0x00).
99 * @param work PROTOCORE_ENOCEAN_BORROW bytes the caller took. Not held past the call.
100 * @param buf Buf
101 * @param len Len
102 * @return The uint8_t.
103 */
104uint8_t protocore_enocean_esp3_crc8(uint8_t *work, const uint8_t *buf, uint16_t len);
105/**
106 * @brief Frame one ESP3 telegram from the front of raw.
107 * @param work PROTOCORE_ENOCEAN_BORROW bytes the caller took. Not held past the call.
108 * @param raw Raw
109 * @param len Len
110 * @param out Out
111 * @return The int.
112 */
113int protocore_enocean_esp3_parse(uint8_t *work, const uint8_t *raw, uint16_t len, protocore_esp3_packet *out);
114/**
115 * @brief Assemble an ESP3 telegram into out.
116 * @param work PROTOCORE_ENOCEAN_BORROW bytes the caller took. Not held past the call.
117 * @param type Type
118 * @param data Data
119 * @param data_len Data len
120 * @param opt Opt
121 * @param opt_len Opt len
122 * @param out Out
123 * @param cap Cap
124 * @return The uint16_t.
125 */
126uint16_t protocore_enocean_esp3_build(uint8_t *work, protocore_esp3_type type, const uint8_t *data, uint16_t data_len,
127 const uint8_t *opt, uint8_t opt_len, uint8_t *out, uint16_t cap);
128/**
129 * @brief Decode an ERP1 radio telegram: RORG + payload + 4-octet sender id + .
130 * @param work PROTOCORE_ENOCEAN_BORROW bytes the caller took. Not held past the call.
131 * @param data Data
132 * @param len Len
133 * @param out Out
134 * @return PROTO_TRUE on success.
135 */
136proto_bool protocore_enocean_erp1_parse(uint8_t *work, const uint8_t *data, uint16_t len, protocore_erp1 *out);
137/**
138 * @brief Assemble an ERP1 radio telegram (the inverse of .
139 * @param work PROTOCORE_ENOCEAN_BORROW bytes the caller took. Not held past the call.
140 * @param out Out
141 * @param cap Cap
142 * @param rorg Rorg
143 * @param payload Payload
144 * @param payload_len Payload len
145 * @param sender_id Sender id
146 * @param status Status
147 * @return The uint16_t.
148 */
149uint16_t protocore_enocean_erp1_build(uint8_t *work, uint8_t *out, uint16_t cap, uint8_t rorg, const uint8_t *payload,
150 uint8_t payload_len, uint32_t sender_id, uint8_t status);
151
152/** @brief Module namespace. */
158
160
161#endif // PROTOCORE_ENOCEAN_H
PROTO_ENUM_PACKED
Application protocol spoken on a listener port or connection slot.
uint16_t protocore_enocean_erp1_build(uint8_t *work, uint8_t *out, uint16_t cap, uint8_t rorg, const uint8_t *payload, uint8_t payload_len, uint32_t sender_id, uint8_t status)
Assemble an ERP1 radio telegram (the inverse of .
proto_bool protocore_enocean_erp1_parse(uint8_t *work, const uint8_t *data, uint16_t len, protocore_erp1 *out)
Decode an ERP1 radio telegram: RORG + payload + 4-octet sender id + .
@ ESP3_RADIO_ERP2
Definition enocean.h:62
@ ESP3_EVENT
Definition enocean.h:58
@ ESP3_RADIO_ERP1
Definition enocean.h:55
@ ESP3_RADIO_SUB_TEL
Definition enocean.h:57
@ ESP3_REMOTE_MAN
Definition enocean.h:61
@ ESP3_SMART_ACK
Definition enocean.h:60
@ ESP3_COMMON_COMMAND
Definition enocean.h:59
@ ESP3_RESPONSE
Definition enocean.h:56
uint8_t protocore_enocean_esp3_crc8(uint8_t *work, const uint8_t *buf, uint16_t len)
CRC-8 used by ESP3 (polynomial 0x07, MSB-first, init 0x00).
int protocore_enocean_esp3_parse(uint8_t *work, const uint8_t *raw, uint16_t len, protocore_esp3_packet *out)
Frame one ESP3 telegram from the front of raw.
enum PROTO_ENUM_PACKED protocore_esp3_type
ESP3 packet types (the common ones).
uint16_t protocore_enocean_esp3_build(uint8_t *work, protocore_esp3_type type, const uint8_t *data, uint16_t data_len, const uint8_t *opt, uint8_t opt_len, uint8_t *out, uint16_t cap)
Assemble an ESP3 telegram into out.
PROTOCORE_NS EnoceanNs Enocean PROTOCORE_UNUSED
Module namespace.
Definition enocean.h:153
#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.
Dispatch table. Addressed by offset, so the layout is asserted below.
Definition enocean.h:87
uint8_t(* esp3_crc8)(uint8_t *, const uint8_t *, uint16_t)
Definition enocean.h:88
A decoded ERP1 radio telegram (the payload aliases the caller's buffer).
Definition enocean.h:77
const uint8_t * payload
RORG-specific data, or nullptr if none.
Definition enocean.h:79
uint8_t rorg
telegram type (PROTOCORE_ERP_RORG_*)
Definition enocean.h:78
uint8_t status
status octet (repeater count + telegram-type bits)
Definition enocean.h:82
uint32_t sender_id
4-octet sender id (big-endian)
Definition enocean.h:81
uint8_t payload_len
payload octets (data length - 6)
Definition enocean.h:80
A parsed ESP3 telegram (pointers alias the caller's buffer).
Definition enocean.h:67
uint8_t opt_len
optional-data length
Definition enocean.h:71
const uint8_t * data
data field
Definition enocean.h:68
uint16_t data_len
data length
Definition enocean.h:70
const uint8_t * opt
optional-data field
Definition enocean.h:69
protocore_esp3_type type
packet type (protocore_esp3_type)
Definition enocean.h:72
#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