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 for storing will update state.
252 : */
253 1 : struct mqtt_sn_will_update {
254 : /** An update message needs to be send */
255 1 : bool in_progress;
256 :
257 : /** Number of retries for failed update attempts */
258 1 : uint8_t retries;
259 :
260 : /** Timestamp of the last update attempt */
261 1 : int64_t last_attempt;
262 : };
263 :
264 : /**
265 : * Structure describing an MQTT-SN client.
266 : */
267 1 : struct mqtt_sn_client {
268 : /** 1-23 character unique client ID */
269 1 : struct mqtt_sn_data client_id;
270 :
271 : /** Topic for Will message.
272 : * Must be initialized before connecting with will=true
273 : */
274 1 : struct mqtt_sn_data will_topic;
275 :
276 : /** Will message.
277 : * Must be initialized before connecting with will=true
278 : */
279 1 : struct mqtt_sn_data will_msg;
280 :
281 : /** Quality of Service for the Will message */
282 1 : enum mqtt_sn_qos will_qos;
283 :
284 : /** Flag indicating if the will message should be retained by the broker */
285 1 : bool will_retain;
286 :
287 : /** Underlying transport to be used by the client */
288 1 : struct mqtt_sn_transport *transport;
289 :
290 : /** Buffer for outgoing data */
291 1 : struct net_buf_simple tx;
292 :
293 : /** Buffer for incoming data */
294 1 : struct net_buf_simple rx;
295 :
296 : /** Buffer for incoming data sender address */
297 1 : struct net_buf_simple rx_addr;
298 :
299 : /** Event callback */
300 1 : mqtt_sn_evt_cb_t evt_cb;
301 :
302 : /** Message ID for the next message to be sent */
303 1 : uint16_t next_msg_id;
304 :
305 : /** List of pending publish messages */
306 1 : sys_slist_t publish;
307 :
308 : /** List of registered topics */
309 1 : sys_slist_t topic;
310 :
311 : /** List of found gateways */
312 1 : sys_slist_t gateway;
313 :
314 : /** Current state of the MQTT-SN client */
315 1 : int state;
316 :
317 : /** Timestamp of the last ping request */
318 1 : int64_t last_ping;
319 :
320 : /** Number of retries for failed ping attempts */
321 1 : uint8_t ping_retries;
322 :
323 : /** Timestamp of the next SEARCHGW transmission */
324 1 : int64_t ts_searchgw;
325 :
326 : /** Timestamp of the next GWINFO transmission */
327 1 : int64_t ts_gwinfo;
328 :
329 : /** Radius of the next GWINFO transmission */
330 1 : int64_t radius_gwinfo;
331 :
332 : /** State for will topic updates */
333 1 : struct mqtt_sn_will_update will_topic_update;
334 :
335 : /** State for will message updates */
336 1 : struct mqtt_sn_will_update will_message_update;
337 :
338 : /** Delayable work structure for processing MQTT-SN events */
339 1 : struct k_work_delayable process_work;
340 : };
341 :
342 : /**
343 : * @brief Initialize a client.
344 : *
345 : * @param client The MQTT-SN client to initialize.
346 : * @param client_id The ID to be used by the client.
347 : * @param transport The transport to be used by the client.
348 : * @param evt_cb The event callback function for the client.
349 : * @param tx Pointer to the transmit buffer.
350 : * @param txsz Size of the transmit buffer.
351 : * @param rx Pointer to the receive buffer.
352 : * @param rxsz Size of the receive buffer.
353 : *
354 : * @return 0 or a negative error code (errno.h) indicating reason of failure.
355 : */
356 1 : int mqtt_sn_client_init(struct mqtt_sn_client *client, const struct mqtt_sn_data *client_id,
357 : struct mqtt_sn_transport *transport, mqtt_sn_evt_cb_t evt_cb, void *tx,
358 : size_t txsz, void *rx, size_t rxsz);
359 :
360 : /**
361 : * @brief Deinitialize the client.
362 : *
363 : * This removes all topics and publishes, and also de-inits the transport.
364 : *
365 : * @param client The MQTT-SN client to deinitialize.
366 : */
367 1 : void mqtt_sn_client_deinit(struct mqtt_sn_client *client);
368 :
369 : /**
370 : * @brief Manually add a Gateway, bypasing the normal search process.
371 : *
372 : * This function manually creates a gateway that is stored internal to the library.
373 : *
374 : * @param client The MQTT-SN client to connect.
375 : * @param gw_id Single byte Gateway Identifier
376 : * @param gw_addr Address data structure to be used by the transport layer.
377 : *
378 : * @return 0 or a negative error code (errno.h) indicating reason of failure.
379 : */
380 1 : int mqtt_sn_add_gw(struct mqtt_sn_client *client, uint8_t gw_id, struct mqtt_sn_data gw_addr);
381 :
382 : /**
383 : * @brief Initiate the MQTT-SN GW Search process.
384 : *
385 : * @param client The MQTT-SN client to connect.
386 : * @param radius Broadcast radius for the search message.
387 : *
388 : * @return 0 or a negative error code (errno.h) indicating reason of failure.
389 : */
390 1 : int mqtt_sn_search(struct mqtt_sn_client *client, uint8_t radius);
391 :
392 : /**
393 : * @brief Connect the client.
394 : *
395 : * @param client The MQTT-SN client to connect.
396 : * @param will Flag indicating if a Will message should be sent.
397 : * @param clean_session Flag indicating if a clean session should be started.
398 : *
399 : * @return 0 or a negative error code (errno.h) indicating reason of failure.
400 : */
401 1 : int mqtt_sn_connect(struct mqtt_sn_client *client, bool will, bool clean_session);
402 :
403 : /**
404 : * @brief Disconnect the client.
405 : *
406 : * @param client The MQTT-SN client to disconnect.
407 : *
408 : * @return 0 or a negative error code (errno.h) indicating reason of failure.
409 : */
410 1 : int mqtt_sn_disconnect(struct mqtt_sn_client *client);
411 :
412 : /**
413 : * @brief Set the client into sleep state.
414 : *
415 : * @param client The MQTT-SN client to be put to sleep.
416 : * @param duration Sleep duration (in seconds).
417 : *
418 : * @return 0 on success, negative errno code on failure.
419 : */
420 1 : int mqtt_sn_sleep(struct mqtt_sn_client *client, uint16_t duration);
421 :
422 : /**
423 : * @brief Subscribe to a given topic.
424 : *
425 : * @param client The MQTT-SN client that should subscribe.
426 : * @param qos The desired quality of service for the subscription.
427 : * @param topic_name The name of the topic to subscribe to.
428 : *
429 : * @return 0 or a negative error code (errno.h) indicating reason of failure.
430 : */
431 1 : int mqtt_sn_subscribe(struct mqtt_sn_client *client, enum mqtt_sn_qos qos,
432 : struct mqtt_sn_data *topic_name);
433 :
434 : /**
435 : * @brief Unsubscribe from a topic.
436 : *
437 : * @param client The MQTT-SN client that should unsubscribe.
438 : * @param qos The quality of service used when subscribing.
439 : * @param topic_name The name of the topic to unsubscribe from.
440 : *
441 : * @return 0 or a negative error code (errno.h) indicating reason of failure.
442 : */
443 1 : int mqtt_sn_unsubscribe(struct mqtt_sn_client *client, enum mqtt_sn_qos qos,
444 : struct mqtt_sn_data *topic_name);
445 :
446 : /**
447 : * @brief Publish a value.
448 : *
449 : * If the topic is not yet registered with the gateway, the library takes care of it.
450 : *
451 : * @param client The MQTT-SN client that should publish.
452 : * @param qos The desired quality of service for the publish.
453 : * @param topic_name The name of the topic to publish to.
454 : * @param retain Flag indicating if the message should be retained by the broker.
455 : * @param data The data to be published.
456 : *
457 : * @return 0 or a negative error code (errno.h) indicating reason of failure.
458 : */
459 1 : int mqtt_sn_publish(struct mqtt_sn_client *client, enum mqtt_sn_qos qos,
460 : struct mqtt_sn_data *topic_name, bool retain, struct mqtt_sn_data *data);
461 :
462 : /**
463 : * @brief Check the transport for new incoming data.
464 : *
465 : * Call this function periodically, or if you have good reason to believe there is any data.
466 : * If the client's transport struct contains a poll-function, this function is non-blocking.
467 : *
468 : * @param client The MQTT-SN client to check for incoming data.
469 : *
470 : * @return 0 or a negative error code (errno.h) indicating reason of failure.
471 : */
472 1 : int mqtt_sn_input(struct mqtt_sn_client *client);
473 :
474 : /**
475 : * @brief Get topic name by topic ID.
476 : *
477 : * @param[in] client The MQTT-SN client that uses this topic.
478 : * @param[in] id Topic identifier.
479 : * @param[out] topic_name Will be assigned to topic name.
480 : *
481 : * @return 0 on success, -ENOENT if topic ID doesn't exist,
482 : * or -EINVAL on invalid arguments.
483 : */
484 1 : int mqtt_sn_get_topic_name(struct mqtt_sn_client *client, uint16_t id,
485 : struct mqtt_sn_data *topic_name);
486 :
487 : /**
488 : * @brief Predefine topic.
489 : *
490 : * Can be called before mqtt_sn_connect, because predefined topics are never cleared. If you call it
491 : * afterwards, it has to be called before calling mqtt_sn_input for the first time after the
492 : * connect, to prevent race conditions where incoming publications use predefined topics which were
493 : * not defined, yet.
494 : *
495 : * @param[in] client The MQTT-SN client to define the topic on.
496 : * @param[in] topic_id Topic identifier.
497 : * @param[in] topic_name The name of the topic.
498 : *
499 : * @return 0 or a negative error code (errno.h) indicating reason of failure.
500 : */
501 1 : int mqtt_sn_predefine_topic(struct mqtt_sn_client *client, uint16_t topic_id,
502 : struct mqtt_sn_data *topic_name);
503 :
504 : /**
505 : * @brief Define a short topic.
506 : *
507 : * Can be called before mqtt_sn_connect, because short topics are never cleared.
508 : *
509 : * @param[in] client The MQTT-SN client to define the topic on.
510 : * @param[in] topic_name The name of the topic. Must be exactly 2 bytes long.
511 : *
512 : * @return 0 or a negative error code (errno.h) indicating reason of failure.
513 : */
514 1 : int mqtt_sn_define_short_topic(struct mqtt_sn_client *client, struct mqtt_sn_data *topic_name);
515 :
516 : /**
517 : * @brief Send a will topic update to the server.
518 : *
519 : * Call this to send the will topic stored in client->will_topic to the server.
520 : * Should be used if you changed the value after connecting. The variables
521 : * client->will_retain and client->will_qos will also be sent as part of the
522 : * update.
523 : *
524 : * @warning Since there is no message ID in the will topic update message,
525 : * this can't be done without race conditions. Contribute to newer
526 : * versions of the specification if you want this to be changed.
527 : *
528 : * @param[in] client The MQTT-SN client to use for sending the update.
529 : *
530 : * @return 0 or a negative error code (errno.h) indicating reason of failure.
531 : */
532 1 : int mqtt_sn_update_will_topic(struct mqtt_sn_client *client);
533 :
534 : /**
535 : * @brief Send a will message update to the server.
536 : *
537 : * Call this to send the will message stored in client->will_msg to the server.
538 : * Should be used if you changed the value after connecting.
539 : *
540 : * @warning Since there is no message ID in the will message update message,
541 : * this can't be done without race conditions. Contribute to newer
542 : * versions of the specification if you want this to be changed.
543 : *
544 : * @param[in] client The MQTT-SN client to use for sending the update.
545 : *
546 : * @return 0 or a negative error code (errno.h) indicating reason of failure.
547 : */
548 1 : int mqtt_sn_update_will_message(struct mqtt_sn_client *client);
549 :
550 : #ifdef __cplusplus
551 : }
552 : #endif
553 :
554 : #endif /* ZEPHYR_INCLUDE_NET_MQTT_SN_H_ */
555 :
556 : /**@} */
|