DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
mqtt_sn.h
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 mqtt_sn.h
6 * @brief MQTT-SN v1.2 wire codec (DETWS_ENABLE_MQTT_SN) - zero-heap message builder +
7 * parser for MQTT for Sensor Networks, the UDP / non-TCP MQTT variant for
8 * constrained, lossy links (topic IDs instead of strings, gateway discovery,
9 * sleeping-client keep-alive).
10 *
11 * Spec: MQTT-SN v1.2 (OASIS contribution). Each message is:
12 * @code
13 * [Length][MsgType][message body...]
14 * @endcode
15 * - Length is 1 octet when the total message length (the Length field included) is
16 * <= 255; otherwise it is 3 octets: `0x01` then a big-endian uint16 total length.
17 * - All multi-byte integers (TopicId, MsgId, Duration) are big-endian (MSB first).
18 * - TopicId / MsgId are 2 octets; topics may be a registered numeric TopicId, a
19 * pre-defined TopicId, or a 2-character short topic name (per the Flags TopicIdType).
20 *
21 * Verified against the Eclipse Paho MQTT-SN reference (message-type enum + length
22 * encoding) and the v1.2 spec. This is the wire codec only; the gateway connection,
23 * topic registry, and retransmission/sleep state are the application's.
24 *
25 * @author Douglas Quigg (dstroy0)
26 * @date 2026
27 */
28
29#ifndef DETERMINISTICESPASYNCWEBSERVER_MQTT_SN_H
30#define DETERMINISTICESPASYNCWEBSERVER_MQTT_SN_H
31
32#include "ServerConfig.h"
33
34#if DETWS_ENABLE_MQTT_SN
35
36#include <stddef.h>
37#include <stdint.h>
38
39#define MQTTSN_LEN3_PREFIX 0x01 ///< a first Length octet of 0x01 signals the 3-octet length form
40
41// Message types (MQTT-SN v1.2 Table 5).
42#define MQTTSN_ADVERTISE 0x00
43#define MQTTSN_SEARCHGW 0x01
44#define MQTTSN_GWINFO 0x02
45#define MQTTSN_CONNECT 0x04
46#define MQTTSN_CONNACK 0x05
47#define MQTTSN_WILLTOPICREQ 0x06
48#define MQTTSN_WILLTOPIC 0x07
49#define MQTTSN_WILLMSGREQ 0x08
50#define MQTTSN_WILLMSG 0x09
51#define MQTTSN_REGISTER 0x0A
52#define MQTTSN_REGACK 0x0B
53#define MQTTSN_PUBLISH 0x0C
54#define MQTTSN_PUBACK 0x0D
55#define MQTTSN_PUBCOMP 0x0E
56#define MQTTSN_PUBREC 0x0F
57#define MQTTSN_PUBREL 0x10
58#define MQTTSN_SUBSCRIBE 0x12
59#define MQTTSN_SUBACK 0x13
60#define MQTTSN_UNSUBSCRIBE 0x14
61#define MQTTSN_UNSUBACK 0x15
62#define MQTTSN_PINGREQ 0x16
63#define MQTTSN_PINGRESP 0x17
64#define MQTTSN_DISCONNECT 0x18
65
66// Flags octet bit layout (MQTT-SN v1.2 sec 5.3.4).
67#define MQTTSN_FLAG_DUP 0x80
68#define MQTTSN_FLAG_QOS_MASK 0x60
69#define MQTTSN_FLAG_QOS_SHIFT 5
70#define MQTTSN_FLAG_RETAIN 0x10
71#define MQTTSN_FLAG_WILL 0x08
72#define MQTTSN_FLAG_CLEAN 0x04
73#define MQTTSN_FLAG_TOPICIDTYPE_MASK 0x03
74
75// TopicIdType values (low 2 bits of Flags).
76#define MQTTSN_TOPIC_NORMAL 0x00 ///< registered numeric topic id (REGISTER)
77#define MQTTSN_TOPIC_PREDEFINED 0x01 ///< pre-defined numeric topic id
78#define MQTTSN_TOPIC_SHORT 0x02 ///< 2-character short topic name
79
80// Return codes (MQTT-SN v1.2 sec 5.3.5).
81#define MQTTSN_RC_ACCEPTED 0x00
82#define MQTTSN_RC_CONGESTION 0x01
83#define MQTTSN_RC_INVALID_TOPIC_ID 0x02
84#define MQTTSN_RC_NOT_SUPPORTED 0x03
85
86#define MQTTSN_PROTOCOL_ID 0x01 ///< CONNECT ProtocolId octet
87
88/** @brief Compose a Flags octet. @p qos is 0..3 (3 = QoS -1); @p topic_id_type is MQTTSN_TOPIC_*. */
89uint8_t mqttsn_make_flags(bool dup, uint8_t qos, bool retain, bool will, bool clean, uint8_t topic_id_type);
90
91// ---- builders (return total bytes written, or 0 on overflow / bad input) ----
92
93/** @brief CONNECT: Flags, ProtocolId(=1), Duration, ClientId. */
94size_t mqttsn_build_connect(uint8_t *buf, size_t cap, uint8_t flags, uint16_t duration, const char *client_id);
95
96/** @brief REGISTER: TopicId (0x0000 from a client), MsgId, TopicName. */
97size_t mqttsn_build_register(uint8_t *buf, size_t cap, uint16_t topic_id, uint16_t msg_id, const char *topic_name);
98
99/** @brief REGACK: TopicId, MsgId, ReturnCode. */
100size_t mqttsn_build_regack(uint8_t *buf, size_t cap, uint16_t topic_id, uint16_t msg_id, uint8_t ret_code);
101
102/** @brief PUBLISH: Flags, TopicId, MsgId, Data. */
103size_t mqttsn_build_publish(uint8_t *buf, size_t cap, uint8_t flags, uint16_t topic_id, uint16_t msg_id,
104 const uint8_t *data, size_t data_len);
105
106/** @brief PUBACK: TopicId, MsgId, ReturnCode. */
107size_t mqttsn_build_puback(uint8_t *buf, size_t cap, uint16_t topic_id, uint16_t msg_id, uint8_t ret_code);
108
109/** @brief SUBSCRIBE by topic name: Flags, MsgId, TopicName (set TopicIdType normal/short in @p flags). */
110size_t mqttsn_build_subscribe_name(uint8_t *buf, size_t cap, uint8_t flags, uint16_t msg_id, const char *topic_name);
111
112/** @brief SUBSCRIBE by pre-defined topic id: Flags, MsgId, TopicId (TopicIdType predefined). */
113size_t mqttsn_build_subscribe_id(uint8_t *buf, size_t cap, uint8_t flags, uint16_t msg_id, uint16_t topic_id);
114
115/** @brief PINGREQ: optional ClientId (nullptr for an empty keep-alive ping). */
116size_t mqttsn_build_pingreq(uint8_t *buf, size_t cap, const char *client_id);
117
118/** @brief DISCONNECT: optional sleep Duration (pass with_duration=false for a plain disconnect). */
119size_t mqttsn_build_disconnect(uint8_t *buf, size_t cap, bool with_duration, uint16_t duration);
120
121/** @brief SEARCHGW: broadcast Radius. */
122size_t mqttsn_build_searchgw(uint8_t *buf, size_t cap, uint8_t radius);
123
124// ---- parsing ----
125
126/** @brief A decoded message header: type + a slice of the body (past the MsgType octet). */
127struct MqttsnHeader
128{
129 uint8_t msg_type;
130 const uint8_t *payload; ///< message body (points INTO the source buffer)
131 size_t payload_len;
132};
133
134/**
135 * @brief Parse the Length + MsgType header at the head of [buf, buf+len).
136 * @param consumed receives the full message length (so the caller can advance).
137 * @return true on a complete, self-consistent message; false if incomplete / malformed.
138 */
139bool mqttsn_parse_header(const uint8_t *buf, size_t len, MqttsnHeader *out, size_t *consumed);
140
141// The typed parsers below take the @ref MqttsnHeader payload/payload_len.
142bool mqttsn_parse_connack(const uint8_t *payload, size_t len, uint8_t *ret_code);
143bool mqttsn_parse_regack(const uint8_t *payload, size_t len, uint16_t *topic_id, uint16_t *msg_id, uint8_t *ret_code);
144bool mqttsn_parse_puback(const uint8_t *payload, size_t len, uint16_t *topic_id, uint16_t *msg_id, uint8_t *ret_code);
145bool mqttsn_parse_suback(const uint8_t *payload, size_t len, uint8_t *flags, uint16_t *topic_id, uint16_t *msg_id,
146 uint8_t *ret_code);
147bool mqttsn_parse_publish(const uint8_t *payload, size_t len, uint8_t *flags, uint16_t *topic_id, uint16_t *msg_id,
148 const uint8_t **data, size_t *data_len);
149bool mqttsn_parse_register(const uint8_t *payload, size_t len, uint16_t *topic_id, uint16_t *msg_id,
150 const char **topic_name, size_t *topic_name_len);
151
152#endif // DETWS_ENABLE_MQTT_SN
153
154#endif // DETERMINISTICESPASYNCWEBSERVER_MQTT_SN_H
User-facing configuration for DeterministicESPAsyncWebServer.