Blame view

RIOT/sys/include/net/emcute.h 13 KB
a752c7ab   elopes   add first test an...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
  /*
   * Copyright (C) 2017 Freie Universitรคt Berlin
   *
   * This file is subject to the terms and conditions of the GNU Lesser
   * General Public License v2.1. See the file LICENSE in the top level
   * directory for more details.
   */
  
  /**
   * @defgroup    net_emcute MQTT-SN Client (emCute)
   * @ingroup     net
   * @brief       emCute, the MQTT-SN implementation for RIOT
   *
   * # About
   * emCute is the implementation of the OASIS MQTT-SN protocol for RIOT. It is
   * designed with a focus on small memory footprint and usability.
   *
   *
   * # Design Decisions and Restrictions
   * * emCute is designed to run on top of UDP only, making use of
   * @ref net_sock_udp. The design is not intended to be used with any other
   * transport.
   *
   * The implementation is based on a 2-thread model: emCute needs one thread of
   * its own, in which receiving of packets and sending of ping messages are
   * handled. All 'user space functions' have to run from (a) different (i.e.
   * user) thread(s). emCute uses thread flags to synchronize between threads.
   *
   * Further know restrictions are:
   * - ASCII topic names only (no support for UTF8 names, yet)
   * - topic length is restricted to fit in a single length byte (248 byte max)
   * - no support for wildcards in topic names. This feature requires more
   *   elaborate internal memory management, supposedly at the cost of quite
   *   increased ROM and RAM usage
   * - no retransmit when receiving a REJ_CONG (reject, reason congestion). when
   *   getting a REJ_CONG (reject, reason congestion), the spec tells us to resend
   *   the original message after T_WAIT (default: >5min). This is not supported,
   *   as this would require to block to calling thread (or keep state) for long
   *   periods of time and is (in Hauke's opinion) not feasible for constrained
   *   nodes.
   *
   *
   * # Error Handling
   * This implementation tries minimize parameter checks to a minimum, checking as
   * many parameters as feasible using assertions. For the sake of run-time
   * stability and usability, typical overflow checks are always done during run-
   * time and explicit error values returned in case of errors.
   *
   *
   * # Implementation state
   * In the current state, emCute supports:
   * - connecting to a gateway
   * - disconnecting from gateway
   * - registering a last will topic and message during connection setup
   * - registering topic names with the gateway (obtaining topic IDs)
   * - subscribing to topics
   * - unsubscribing from topics
   * - updating will topic
   * - updating will message
   * - sending out periodic PINGREQ messages
   * - handling re-transmits
   *
   * The following features are however still missing (but planned):
   * @todo        Gateway discovery (so far there is no support for handling
   *              ADVERTISE, GWINFO, and SEARCHGW). Open question to answer here:
   *              how to put / how to encode the IPv(4/6) address AND the port of
   *              a gateway in the GwAdd field of the GWINFO message
   * @todo        QOS level 2
   * @todo        put the node to sleep (send DISCONNECT with duration field set)
   * @todo        handle DISCONNECT messages initiated by the broker/gateway
   * @todo        support for pre-defined and short topic IDs
   * @todo        handle (previously) active subscriptions on reconnect/disconnect
   * @todo        handle re-connect/disconnect from unresponsive gateway (in case
   *              a number of ping requests are unanswered)
   * @todo        react only to incoming ping requests that are actually send by
   *              the gateway we are connected to
   *
   * @{
   * @file
   * @brief       emCute MQTT-SN interface definition
   *
   * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
   */
  
  #ifndef NET_EMCUTE_H
  #define NET_EMCUTE_H
  
  #include <stdint.h>
  #include <stddef.h>
  #include <stdbool.h>
  
  #include "net/sock/udp.h"
  
  #ifdef __cplusplus
  extern "C" {
  #endif
  
  #ifndef EMCUTE_DEFAULT_PORT
  /**
   * @brief   Default UDP port to listen on (also used as SRC port)
   */
  #define EMCUTE_DEFAULT_PORT     (1883U)
  #endif
  
  #ifndef EMCUTE_BUFSIZE
  /**
   * @brief   Buffer size used for emCute's transmit and receive buffers
   *
   * @note    The buffer size MUST be less than 32768 on 16-bit and 8-bit
   *          platforms to prevent buffer overflows.
   *
   * The overall buffer size used by emCute is this value time two (Rx + Tx).
   */
  #define EMCUTE_BUFSIZE          (512U)
  #endif
  
  #ifndef EMCUTE_ID_MAXLEN
  /**
   * @brief   Maximum client ID length
   *
   * @note    **Must** be less than (256 - 6) AND less than
   *          (@ref EMCUTE_BUFSIZE - 6).
   */
  #define EMCUTE_ID_MAXLEN        (196U)
  #endif
  
  #ifndef EMCUTE_TOPIC_MAXLEN
  /**
   * @brief   Maximum topic length
   *
   * @note    **Must** be less than (256 - 6) AND less than
   *          (@ref EMCUTE_BUFSIZE - 6).
   */
  #define EMCUTE_TOPIC_MAXLEN     (196U)
  #endif
  
  #ifndef EMCUTE_KEEPALIVE
  /**
   * @brief   Keep-alive interval [in s]
   *
   * The node will communicate this interval to the gateway send a ping message
   * every time when this amount of time has passed.
   *
   * For the default value, see spec v1.2, section 7.2 -> T_WAIT: > 5 min
   */
  #define EMCUTE_KEEPALIVE        (360)       /* -> 6 min*/
  #endif
  
  #ifndef EMCUTE_T_RETRY
  /**
   * @brief   Re-send interval [in seconds]
   *
   * For the default value, see spec v1.2, section 7.2 -> T_RETRY: 10 to 15 sec
   */
  #define EMCUTE_T_RETRY          (15U)       /* -> 15 sec */
  #endif
  
  #ifndef EMCUTE_N_RETRY
  /**
   * @brief   Number of retries when sending packets
   *
   * For the default value, see spec v1.2, section 7.2 -> N_RETRY: 3-5
   */
  #define EMCUTE_N_RETRY          (3U)
  #endif
  
  /**
   * @brief   MQTT-SN flags
   *
   * All MQTT-SN functions only support a sub-set of the available flags. It is up
   * to the user to only supply valid/supported flags to a function. emCute will
   * trigger assertion fails on the use of unsupported flags (if compiled with
   * DEVELHELP).
   *
   * Refer to the MQTT-SN spec section 5.3.4 for further information.
   */
  enum {
      EMCUTE_DUP        = 0x80,   /**< duplicate flag */
      EMCUTE_QOS_MASK   = 0x60,   /**< QoS level mask */
      EMCUTE_QOS_2      = 0x40,   /**< QoS level 2 */
      EMCUTE_QOS_1      = 0x20,   /**< QoS level 1 */
      EMCUTE_QOS_0      = 0x00,   /**< QoS level 0 */
      EMCUTE_RETAIN     = 0x10,   /**< retain flag */
      EMCUTE_WILL       = 0x08,   /**< will flag, used during CONNECT */
      EMCUTE_CS         = 0x04,   /**< clean session flag */
      EMCUTE_TIT_MASK   = 0x03,   /**< topic ID type mask */
      EMCUTE_TIT_SHORT  = 0x02,   /**< topic ID: short */
      EMCUTE_TIT_PREDEF = 0x01,   /**< topic ID: pre-defined */
      EMCUTE_TIT_NORMAL = 0x00    /**< topic ID: normal */
  };
  
  /**
   * @brief   Possible emCute return values
   */
  enum {
      EMCUTE_OK       =  0,       /**< everything went as expect */
      EMCUTE_NOGW     = -1,       /**< error: not connected to a gateway */
      EMCUTE_REJECT   = -2,       /**< error: operation was rejected by broker */
      EMCUTE_OVERFLOW = -3,       /**< error: ran out of buffer space */
      EMCUTE_TIMEOUT  = -4,       /**< error: timeout */
      EMCUTE_NOTSUP   = -5        /**< error: feature not supported */
  };
  
  /**
   * @brief   MQTT-SN topic
   */
  typedef struct {
      const char *name;           /**< topic string (currently ACSII only) */
      uint16_t id;                /**< topic id, as assigned by the gateway */
  } emcute_topic_t;
  
  /**
   * @brief   Signature for callbacks fired when publish messages are received
   *
   * @param[in] topic     topic the received data was published on
   * @param[in] data      published data, can be NULL
   * @param[in] len       length of @p data in bytes
   */
  typedef void(*emcute_cb_t)(const emcute_topic_t *topic, void *data, size_t len);
  
  /**
   * @brief   Data-structure for keeping track of topics we register to
   */
  typedef struct emcute_sub {
      struct emcute_sub *next;    /**< next subscription (saved in a list) */
      emcute_topic_t topic;       /**< topic we subscribe to */
      emcute_cb_t cb;             /**< function called when receiving messages */
      void *arg;                  /**< optional custom argument */
  } emcute_sub_t;
  
  /**
   * @brief   Connect to a given MQTT-SN gateway (CONNECT)
   *
   * When called while already connected to a gateway, call emcute_discon() first
   * to disconnect from the current gateway.
   *
   * @param[in] remote        address and port of the target MQTT-SN gateway
   * @param[in] clean         set to true to start a clean session
   * @param[in] will_topic    last will topic name, no last will will be
   *                          configured if set to NULL
   * @param[in] will_msg      last will message content, will be ignored if
   *                          @p will_topic is set to NULL
   * @param[in] will_msg_len  length of @p will_msg in byte
   * @param[in] flags         flags used for the last will, allowed are retain and
   *                          QoS
   *
   * @return  EMCUTE_OK on success
   * @return  EMCUTE_NOGW if already connected to a gateway
   * @return  EMCUTE_REJECT on connection refused by gateway
   * @return  EMCUTE_TIMEOUT on connection timeout
   */
  int emcute_con(sock_udp_ep_t *remote, bool clean, const char *will_topic,
                 const void *will_msg, size_t will_msg_len, unsigned flags);
  
  /**
   * @brief   Disconnect from the gateway we are currently connected to
   *
   * @return  EMCUTE_OK on success
   * @return  EMCUTE_GW if not connected to a gateway
   * @return  EMCUTE_TIMEOUT on response timeout
   */
  int emcute_discon(void);
  
  /**
   * @brief   Get a topic ID for the given topic name from the gateway
   *
   * @param[in,out] topic     topic to register, topic.name **must not** be NULL
   *
   * @return  EMCUTE_OK on success
   * @return  EMCUTE_NOGW if not connected to a gateway
   * @return  EMCUTE_OVERFLOW if length of topic name exceeds
   *          @ref EMCUTE_TOPIC_MAXLEN
   * @return  EMCUTE_TIMEOUT on connection timeout
   */
  int emcute_reg(emcute_topic_t *topic);
  
  /**
   * @brief   Publish data on the given topic
   *
   * @param[in] topic     topic to send data to, topic **must** be registered
   *                      (topic.id **must** populated).
   * @param[in] buf       data to publish
   * @param[in] len       length of @p data in bytes
   * @param[in] flags     flags used for publication, allowed are QoS and retain
   *
   * @return  EMCUTE_OK on success
   * @return  EMCUTE_NOGW if not connected to a gateway
   * @return  EMCUTE_REJECT if publish message was rejected (QoS > 0 only)
   * @return  EMCUTE_OVERFLOW if length of data exceeds @ref EMCUTE_BUFSIZE
   * @return  EMCUTE_TIMEOUT on connection timeout (QoS > 0 only)
   * @return  EMCUTE_NOTSUP on unsupported flag values
   */
  int emcute_pub(emcute_topic_t *topic, const void *buf, size_t len,
                 unsigned flags);
  
  /**
   * @brief   Subscribe to the given topic
   *
   * When calling this function, @p sub->topic.name and @p sub->cb **must** be
   * set.
   *
   * @param[in,out] sub   subscription context, @p sub->topic.name and @p sub->cb
   *                      **must** not be NULL.
   * @param[in] flags     flags used when subscribing, allowed are QoS, DUP, and
   *                      topic ID type
   *
   * @return  EMCUTE_OK on success
   * @return  EMCUTE_NOGW if not connected to a gateway
   * @return  EMCUTE_OVERFLOW if length of topic name exceeds
   *          @ref EMCUTE_TOPIC_MAXLEN
   * @return  EMCUTE_TIMEOUT on connection timeout
   */
  int emcute_sub(emcute_sub_t *sub, unsigned flags);
  
  /**
   * @brief   Unsubscripbe the given topic
   *
   * @param[in] sub       subscription context
   *
   * @return  EMCUTE_OK on success
   * @return  EMCUTE_NOGW if not connected to a gateway
   * @return  EMCUTE_TIMEOUT on connection timeout
   */
  int emcute_unsub(emcute_sub_t *sub);
  
  /**
   * @brief   Update the last will topic
   *
   * @param[in] topic     new last will topic
   * @param[in] flags     flags used for the topic, allowed are QoS and retain
   *
   * @return  EMCUTE_OK on success
   * @return  EMCUTE_NOGW if not connected to a gateway
   * @return  EMCUTE_OVERFLOW if length of topic name exceeds
   *          @ref EMCUTE_TOPIC_MAXLEN
   * @return  EMCUTE_REJECT on rejection by the gateway
   * @return  EMCUTE_TIMEOUT on response timeout
   */
  int emcute_willupd_topic(const char *topic, unsigned flags);
  
  /**
   * @brief   Update the last will message
   *
   * @param[in] data      new message to send on last will
   * @param[in] len       length of @p data in bytes
   *
   * @return  EMCUTE_OK on success
   * @return  EMCUTE_NOGW if not connected to a gateway
   * @return  EMCUTE_OVERFLOW if length of the given message exceeds
   *          @ref EMCUTE_BUFSIZE
   * @return  EMCUTE_REJECT on rejection by the gateway
   * @return  EMCUTE_TIMEOUT on response timeout
   */
  int emcute_willupd_msg(const void *data, size_t len);
  
  /**
   * @brief   Run emCute, will 'occupy' the calling thread
   *
   * This function will run the emCute message receiver. It will block the thread
   * it is running in.
   *
   * @param[in] port      UDP port used for listening (default: 1883)
   * @param[in] id        client ID (should be unique)
   */
  void emcute_run(uint16_t port, const char *id);
  
  /**
   * @brief   Return the string representation of the given type value
   *
   * This function is for debugging purposes.
   *
   * @param[in] type      MQTT-SN message type
   *
   * @return  string representation of the given type
   * @return  'UNKNOWN' on invalid type value
   */
  const char *emcute_type_str(uint8_t type);
  
  #ifdef __cplusplus
  }
  #endif
  
  #endif /* NET_EMCUTE_H */
  /** @} */