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