Line data Source code
1 1 : /*
2 : * Copyright (c) 2022 René Beckmann
3 : *
4 : * SPDX-License-Identifier: Apache-2.0
5 : */
6 :
7 : /** @file mqtt_sn.h
8 : *
9 : * @brief MQTT-SN Client Implementation
10 : *
11 : * @details
12 : * MQTT-SN Client's Application interface is defined in this header.
13 : * Targets protocol version 1.2.
14 : *
15 : * @defgroup mqtt_sn_socket MQTT-SN Client library
16 : * @since 3.3
17 : * @version 0.1.0
18 : * @ingroup networking
19 : * @{
20 : */
21 :
22 : #ifndef ZEPHYR_INCLUDE_NET_MQTT_SN_H_
23 : #define ZEPHYR_INCLUDE_NET_MQTT_SN_H_
24 :
25 : #include <stddef.h>
26 :
27 : #include <zephyr/net_buf.h>
28 : #include <zephyr/types.h>
29 :
30 : #include <sys/types.h>
31 :
32 : #ifdef CONFIG_MQTT_SN_TRANSPORT_UDP
33 : #include <zephyr/net/net_ip.h>
34 : #endif
35 :
36 : #ifdef __cplusplus
37 : extern "C" {
38 : #endif
39 :
40 : /**
41 : * Quality of Service. QoS 0-2 work the same as basic MQTT, QoS -1 is an MQTT-SN addition.
42 : * QOS -1 is not supported yet.
43 : */
44 1 : enum mqtt_sn_qos {
45 : MQTT_SN_QOS_0, /**< QOS 0 */
46 : MQTT_SN_QOS_1, /**< QOS 1 */
47 : MQTT_SN_QOS_2, /**< QOS 2 */
48 : MQTT_SN_QOS_M1 /**< QOS -1 */
49 : };
50 :
51 : /**
52 : * MQTT-SN topic types.
53 : */
54 1 : enum mqtt_sn_topic_type {
55 : /**
56 : * Normal topic.
57 : * It allows usage of any valid UTF-8 string as a topic name.
58 : */
59 : MQTT_SN_TOPIC_TYPE_NORMAL,
60 : /**
61 : * Pre-defined topic.
62 : * It allows usage of a two-byte identifier representing a topic name for
63 : * which the corresponding topic name is known in advance by both the client
64 : * and the gateway/server.
65 : */
66 : MQTT_SN_TOPIC_TYPE_PREDEF,
67 : /**
68 : * Short topic.
69 : * It allows usage of a two-byte string as a topic name.
70 : */
71 : MQTT_SN_TOPIC_TYPE_SHORT
72 : };
73 :
74 : /**
75 : * MQTT-SN return codes.
76 : */
77 1 : enum mqtt_sn_return_code {
78 : MQTT_SN_CODE_ACCEPTED = 0x00, /**< Accepted */
79 : MQTT_SN_CODE_REJECTED_CONGESTION = 0x01, /**< Rejected: congestion */
80 : MQTT_SN_CODE_REJECTED_TOPIC_ID = 0x02, /**< Rejected: Invalid Topic ID */
81 : MQTT_SN_CODE_REJECTED_NOTSUP = 0x03, /**< Rejected: Not Supported */
82 : };
83 :
84 : /** @brief Abstracts memory buffers. */
85 1 : struct mqtt_sn_data {
86 1 : const uint8_t *data; /**< Pointer to data. */
87 1 : size_t size; /**< Size of data, in bytes. */
88 : };
89 :
90 : /**
91 : * @brief Initialize memory buffer from C literal string.
92 : *
93 : * Use it as follows:
94 : *
95 : * struct mqtt_sn_data topic = MQTT_SN_DATA_STRING_LITERAL("/zephyr");
96 : *
97 : * @param[in] literal Literal string from which to generate mqtt_sn_data object.
98 : */
99 1 : #define MQTT_SN_DATA_STRING_LITERAL(literal) ((struct mqtt_sn_data){literal, sizeof(literal) - 1})
100 :
101 : /**
102 : * @brief Initialize memory buffer from single bytes.
103 : *
104 : * Use it as follows:
105 : *
106 : * struct mqtt_sn_data data = MQTT_SN_DATA_BYTES(0x13, 0x37);
107 : */
108 1 : #define MQTT_SN_DATA_BYTES(...) \
109 : ((struct mqtt_sn_data){(uint8_t[]){__VA_ARGS__}, sizeof((uint8_t[]){__VA_ARGS__})})
110 :
111 : /**
112 : * Event types that can be emitted by the library.
113 : */
114 1 : enum mqtt_sn_evt_type {
115 : MQTT_SN_EVT_CONNECTED, /**< Connected to a gateway */
116 : MQTT_SN_EVT_DISCONNECTED, /**< Disconnected */
117 : MQTT_SN_EVT_ASLEEP, /**< Entered ASLEEP state */
118 : MQTT_SN_EVT_AWAKE, /**< Entered AWAKE state */
119 : MQTT_SN_EVT_PUBLISH, /**< Received a PUBLISH message */
120 : MQTT_SN_EVT_PINGRESP, /**< Received a PINGRESP */
121 : MQTT_SN_EVT_ADVERTISE, /**< Received a ADVERTISE */
122 : MQTT_SN_EVT_GWINFO, /**< Received a GWINFO */
123 : MQTT_SN_EVT_SEARCHGW /**< Received a SEARCHGW */
124 : };
125 :
126 : /**
127 : * Event metadata.
128 : */
129 1 : union mqtt_sn_evt_param {
130 : /** Structure holding publish event details */
131 : struct {
132 : /** The payload data associated with the event */
133 1 : struct mqtt_sn_data data;
134 : /** The type of topic for the event */
135 1 : enum mqtt_sn_topic_type topic_type;
136 : /** The identifier for the topic of the event */
137 1 : uint16_t topic_id;
138 1 : } publish;
139 : };
140 :
141 : /**
142 : * MQTT-SN event structure to be handled by the event callback.
143 : */
144 1 : struct mqtt_sn_evt {
145 : /** Event type */
146 1 : enum mqtt_sn_evt_type type;
147 : /** Event parameters */
148 1 : union mqtt_sn_evt_param param;
149 : };
150 :
151 : struct mqtt_sn_client;
152 :
153 : /**
154 : * @brief Asynchronous event notification callback registered by the
155 : * application.
156 : *
157 : * @param[in] client Identifies the client for which the event is notified.
158 : * @param[in] evt Event description along with result and associated
159 : * parameters (if any).
160 : */
161 1 : typedef void (*mqtt_sn_evt_cb_t)(struct mqtt_sn_client *client, const struct mqtt_sn_evt *evt);
162 :
163 : /**
164 : * @brief Structure to describe an MQTT-SN transport.
165 : *
166 : * MQTT-SN does not require transports to be reliable or to hold a connection.
167 : * Transports just need to be frame-based, so you can use UDP, ZigBee, or even
168 : * a simple UART, given some kind of framing protocol is used.
169 : */
170 1 : struct mqtt_sn_transport {
171 : /**
172 : * @brief Will be called once on client init to initialize the transport.
173 : *
174 : * Use this to open sockets or similar. May be NULL.
175 : */
176 1 : int (*init)(struct mqtt_sn_transport *transport);
177 :
178 : /**
179 : * @brief Will be called on client deinit
180 : *
181 : * Use this to close sockets or similar. May be NULL.
182 : */
183 1 : void (*deinit)(struct mqtt_sn_transport *transport);
184 :
185 : /**
186 : * @brief Will be called by the library when it wants to send a message.
187 : *
188 : * Implementations should follow sendto conventions with exceptions.
189 : * When dest_addr == NULL, message should be broadcast with addrlen being
190 : * the broadcast radius. This should also handle setting up/destroying
191 : * connections as required when the address changes.
192 : *
193 : * @return ENOERR on connection+transmission success, Negative values
194 : * signal errors.
195 : */
196 1 : int (*sendto)(struct mqtt_sn_client *client, void *buf, size_t sz, const void *dest_addr,
197 : size_t addrlen);
198 :
199 : /**
200 : * @brief Will be called by the library when it wants to receive a message.
201 : *
202 : * Implementations should follow recvfrom conventions with the exception
203 : * of a NULL src_addr being a broadcast message.
204 : */
205 1 : ssize_t (*recvfrom)(struct mqtt_sn_client *client, void *rx_buf, size_t rx_len,
206 : void *src_addr, size_t *addrlen);
207 :
208 : /**
209 : * @brief Check if incoming data is available.
210 : *
211 : * If poll() returns a positive number, recv must not block.
212 : *
213 : * May be NULL, but recv should not block then either.
214 : *
215 : * @return Positive number if data is available, or zero if there is none.
216 : * Negative values signal errors.
217 : */
218 1 : int (*poll)(struct mqtt_sn_client *client);
219 : };
220 :
221 : #ifdef CONFIG_MQTT_SN_TRANSPORT_UDP
222 : /**
223 : * Transport struct for UDP based transport.
224 : */
225 : struct mqtt_sn_transport_udp {
226 : /** Parent struct */
227 : struct mqtt_sn_transport tp;
228 :
229 : /** Socket FD */
230 : int sock;
231 :
232 : /** Address of broadcasts */
233 : struct sockaddr bcaddr;
234 : socklen_t bcaddrlen;
235 : };
236 :
237 : #define UDP_TRANSPORT(transport) CONTAINER_OF(transport, struct mqtt_sn_transport_udp, tp)
238 :
239 : /**
240 : * @brief Initialize the UDP transport.
241 : *
242 : * @param[in] udp The transport to be initialized
243 : * @param[in] gwaddr Pre-initialized gateway address
244 : * @param[in] addrlen Size of the gwaddr structure.
245 : */
246 : int mqtt_sn_transport_udp_init(struct mqtt_sn_transport_udp *udp, struct sockaddr *gwaddr,
247 : socklen_t addrlen);
248 : #endif
249 :
250 : /**
251 : * Structure describing an MQTT-SN client.
252 : */
253 1 : struct mqtt_sn_client {
254 : /** 1-23 character unique client ID */
255 1 : struct mqtt_sn_data client_id;
256 :
257 : /** Topic for Will message.
258 : * Must be initialized before connecting with will=true
259 : */
260 1 : struct mqtt_sn_data will_topic;
261 :
262 : /** Will message.
263 : * Must be initialized before connecting with will=true
264 : */
265 1 : struct mqtt_sn_data will_msg;
266 :
267 : /** Quality of Service for the Will message */
268 1 : enum mqtt_sn_qos will_qos;
269 :
270 : /** Flag indicating if the will message should be retained by the broker */
271 1 : bool will_retain;
272 :
273 : /** Underlying transport to be used by the client */
274 1 : struct mqtt_sn_transport *transport;
275 :
276 : /** Buffer for outgoing data */
277 1 : struct net_buf_simple tx;
278 :
279 : /** Buffer for incoming data */
280 1 : struct net_buf_simple rx;
281 :
282 : /** Buffer for incoming data sender address */
283 1 : struct net_buf_simple rx_addr;
284 :
285 : /** Event callback */
286 1 : mqtt_sn_evt_cb_t evt_cb;
287 :
288 : /** Message ID for the next message to be sent */
289 1 : uint16_t next_msg_id;
290 :
291 : /** List of pending publish messages */
292 1 : sys_slist_t publish;
293 :
294 : /** List of registered topics */
295 1 : sys_slist_t topic;
296 :
297 : /** List of found gateways */
298 1 : sys_slist_t gateway;
299 :
300 : /** Current state of the MQTT-SN client */
301 1 : int state;
302 :
303 : /** Timestamp of the last ping request */
304 1 : int64_t last_ping;
305 :
306 : /** Number of retries for failed ping attempts */
307 1 : uint8_t ping_retries;
308 :
309 : /** Timestamp of the next SEARCHGW transmission */
310 1 : int64_t ts_searchgw;
311 :
312 : /** Timestamp of the next GWINFO transmission */
313 1 : int64_t ts_gwinfo;
314 :
315 : /** Radius of the next GWINFO transmission */
316 1 : int64_t radius_gwinfo;
317 :
318 : /** Delayable work structure for processing MQTT-SN events */
319 1 : struct k_work_delayable process_work;
320 : };
321 :
322 : /**
323 : * @brief Initialize a client.
324 : *
325 : * @param client The MQTT-SN client to initialize.
326 : * @param client_id The ID to be used by the client.
327 : * @param transport The transport to be used by the client.
328 : * @param evt_cb The event callback function for the client.
329 : * @param tx Pointer to the transmit buffer.
330 : * @param txsz Size of the transmit buffer.
331 : * @param rx Pointer to the receive buffer.
332 : * @param rxsz Size of the receive buffer.
333 : *
334 : * @return 0 or a negative error code (errno.h) indicating reason of failure.
335 : */
336 1 : int mqtt_sn_client_init(struct mqtt_sn_client *client, const struct mqtt_sn_data *client_id,
337 : struct mqtt_sn_transport *transport, mqtt_sn_evt_cb_t evt_cb, void *tx,
338 : size_t txsz, void *rx, size_t rxsz);
339 :
340 : /**
341 : * @brief Deinitialize the client.
342 : *
343 : * This removes all topics and publishes, and also de-inits the transport.
344 : *
345 : * @param client The MQTT-SN client to deinitialize.
346 : */
347 1 : void mqtt_sn_client_deinit(struct mqtt_sn_client *client);
348 :
349 : /**
350 : * @brief Manually add a Gateway, bypasing the normal search process.
351 : *
352 : * This function manually creates a gateway that is stored internal to the library.
353 : *
354 : * @param client The MQTT-SN client to connect.
355 : * @param gw_id Single byte Gateway Identifier
356 : * @param gw_addr Address data structure to be used by the transport layer.
357 : *
358 : * @return 0 or a negative error code (errno.h) indicating reason of failure.
359 : */
360 1 : int mqtt_sn_add_gw(struct mqtt_sn_client *client, uint8_t gw_id, struct mqtt_sn_data gw_addr);
361 :
362 : /**
363 : * @brief Initiate the MQTT-SN GW Search process.
364 : *
365 : * @param client The MQTT-SN client to connect.
366 : * @param radius Broadcast radius for the search message.
367 : *
368 : * @return 0 or a negative error code (errno.h) indicating reason of failure.
369 : */
370 1 : int mqtt_sn_search(struct mqtt_sn_client *client, uint8_t radius);
371 :
372 : /**
373 : * @brief Connect the client.
374 : *
375 : * @param client The MQTT-SN client to connect.
376 : * @param will Flag indicating if a Will message should be sent.
377 : * @param clean_session Flag indicating if a clean session should be started.
378 : *
379 : * @return 0 or a negative error code (errno.h) indicating reason of failure.
380 : */
381 1 : int mqtt_sn_connect(struct mqtt_sn_client *client, bool will, bool clean_session);
382 :
383 : /**
384 : * @brief Disconnect the client.
385 : *
386 : * @param client The MQTT-SN client to disconnect.
387 : *
388 : * @return 0 or a negative error code (errno.h) indicating reason of failure.
389 : */
390 1 : int mqtt_sn_disconnect(struct mqtt_sn_client *client);
391 :
392 : /**
393 : * @brief Set the client into sleep state.
394 : *
395 : * @param client The MQTT-SN client to be put to sleep.
396 : * @param duration Sleep duration (in seconds).
397 : *
398 : * @return 0 on success, negative errno code on failure.
399 : */
400 1 : int mqtt_sn_sleep(struct mqtt_sn_client *client, uint16_t duration);
401 :
402 : /**
403 : * @brief Subscribe to a given topic.
404 : *
405 : * @param client The MQTT-SN client that should subscribe.
406 : * @param qos The desired quality of service for the subscription.
407 : * @param topic_name The name of the topic to subscribe to.
408 : *
409 : * @return 0 or a negative error code (errno.h) indicating reason of failure.
410 : */
411 1 : int mqtt_sn_subscribe(struct mqtt_sn_client *client, enum mqtt_sn_qos qos,
412 : struct mqtt_sn_data *topic_name);
413 :
414 : /**
415 : * @brief Unsubscribe from a topic.
416 : *
417 : * @param client The MQTT-SN client that should unsubscribe.
418 : * @param qos The quality of service used when subscribing.
419 : * @param topic_name The name of the topic to unsubscribe from.
420 : *
421 : * @return 0 or a negative error code (errno.h) indicating reason of failure.
422 : */
423 1 : int mqtt_sn_unsubscribe(struct mqtt_sn_client *client, enum mqtt_sn_qos qos,
424 : struct mqtt_sn_data *topic_name);
425 :
426 : /**
427 : * @brief Publish a value.
428 : *
429 : * If the topic is not yet registered with the gateway, the library takes care of it.
430 : *
431 : * @param client The MQTT-SN client that should publish.
432 : * @param qos The desired quality of service for the publish.
433 : * @param topic_name The name of the topic to publish to.
434 : * @param retain Flag indicating if the message should be retained by the broker.
435 : * @param data The data to be published.
436 : *
437 : * @return 0 or a negative error code (errno.h) indicating reason of failure.
438 : */
439 1 : int mqtt_sn_publish(struct mqtt_sn_client *client, enum mqtt_sn_qos qos,
440 : struct mqtt_sn_data *topic_name, bool retain, struct mqtt_sn_data *data);
441 :
442 : /**
443 : * @brief Check the transport for new incoming data.
444 : *
445 : * Call this function periodically, or if you have good reason to believe there is any data.
446 : * If the client's transport struct contains a poll-function, this function is non-blocking.
447 : *
448 : * @param client The MQTT-SN client to check for incoming data.
449 : *
450 : * @return 0 or a negative error code (errno.h) indicating reason of failure.
451 : */
452 1 : int mqtt_sn_input(struct mqtt_sn_client *client);
453 :
454 : /**
455 : * @brief Get topic name by topic ID.
456 : *
457 : * @param[in] client The MQTT-SN client that uses this topic.
458 : * @param[in] id Topic identifier.
459 : * @param[out] topic_name Will be assigned to topic name.
460 : *
461 : * @return 0 on success, -ENOENT if topic ID doesn't exist,
462 : * or -EINVAL on invalid arguments.
463 : */
464 1 : int mqtt_sn_get_topic_name(struct mqtt_sn_client *client, uint16_t id,
465 : struct mqtt_sn_data *topic_name);
466 :
467 : #ifdef __cplusplus
468 : }
469 : #endif
470 :
471 : #endif /* ZEPHYR_INCLUDE_NET_MQTT_SN_H_ */
472 :
473 : /**@} */
|