1/**
2 * @file
3 * MQTT client
4 */
5
6/*
7 * Copyright (c) 2016 Erik Andersson
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without modification,
11 * are permitted provided that the following conditions are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright notice,
14 *    this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright notice,
16 *    this list of conditions and the following disclaimer in the documentation
17 *    and/or other materials provided with the distribution.
18 * 3. The name of the author may not be used to endorse or promote products
19 *    derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
24 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
30 * OF SUCH DAMAGE.
31 *
32 * This file is part of the lwIP TCP/IP stack.
33 *
34 * Author: Erik Andersson
35 *
36 */
37#ifndef LWIP_HDR_APPS_MQTT_CLIENT_H
38#define LWIP_HDR_APPS_MQTT_CLIENT_H
39
40#include "lwip/apps/mqtt_opts.h"
41#include "lwip/err.h"
42#include "lwip/ip_addr.h"
43
44#ifdef __cplusplus
45extern "C" {
46#endif
47
48typedef struct mqtt_client_t mqtt_client_t;
49
50/** @ingroup mqtt
51 * Default MQTT port */
52#define MQTT_PORT 1883
53
54/*---------------------------------------------------------------------------------------------- */
55/* Connection with server */
56
57/**
58 * @ingroup mqtt
59 * Client information and connection parameters */
60struct mqtt_connect_client_info_t {
61  /** Client identifier, must be set by caller */
62  const char *client_id;
63  /** User name and password, set to NULL if not used */
64  const char* client_user;
65  const char* client_pass;
66  /** keep alive time in seconds, 0 to disable keep alive functionality*/
67  u16_t keep_alive;
68  /** will topic, set to NULL if will is not to be used,
69      will_msg, will_qos and will retain are then ignored */
70  const char* will_topic;
71  const char* will_msg;
72  u8_t will_qos;
73  u8_t will_retain;
74};
75
76/**
77 * @ingroup mqtt
78 * Connection status codes */
79typedef enum
80{
81  MQTT_CONNECT_ACCEPTED                 = 0,
82  MQTT_CONNECT_REFUSED_PROTOCOL_VERSION = 1,
83  MQTT_CONNECT_REFUSED_IDENTIFIER       = 2,
84  MQTT_CONNECT_REFUSED_SERVER           = 3,
85  MQTT_CONNECT_REFUSED_USERNAME_PASS    = 4,
86  MQTT_CONNECT_REFUSED_NOT_AUTHORIZED_  = 5,
87  MQTT_CONNECT_DISCONNECTED             = 256,
88  MQTT_CONNECT_TIMEOUT                  = 257
89} mqtt_connection_status_t;
90
91/**
92 * @ingroup mqtt
93 * Function prototype for mqtt connection status callback. Called when
94 * client has connected to the server after initiating a mqtt connection attempt by
95 * calling mqtt_connect() or when connection is closed by server or an error
96 *
97 * @param client MQTT client itself
98 * @param arg Additional argument to pass to the callback function
99 * @param status Connect result code or disconnection notification @see mqtt_connection_status_t
100 *
101 */
102typedef void (*mqtt_connection_cb_t)(mqtt_client_t *client, void *arg, mqtt_connection_status_t status);
103
104
105/**
106 * @ingroup mqtt
107 * Data callback flags */
108enum {
109  /** Flag set when last fragment of data arrives in data callback */
110  MQTT_DATA_FLAG_LAST = 1
111};
112
113/**
114 * @ingroup mqtt
115 * Function prototype for MQTT incoming publish data callback function. Called when data
116 * arrives to a subscribed topic @see mqtt_subscribe
117 *
118 * @param arg Additional argument to pass to the callback function
119 * @param data User data, pointed object, data may not be referenced after callback return,
120          NULL is passed when all publish data are delivered
121 * @param len Length of publish data fragment
122 * @param flags MQTT_DATA_FLAG_LAST set when this call contains the last part of data from publish message
123 *
124 */
125typedef void (*mqtt_incoming_data_cb_t)(void *arg, const u8_t *data, u16_t len, u8_t flags);
126
127
128/**
129 * @ingroup mqtt
130 * Function prototype for MQTT incoming publish function. Called when an incoming publish
131 * arrives to a subscribed topic @see mqtt_subscribe
132 *
133 * @param arg Additional argument to pass to the callback function
134 * @param topic Zero terminated Topic text string, topic may not be referenced after callback return
135 * @param tot_len Total length of publish data, if set to 0 (no publish payload) data callback will not be invoked
136 */
137typedef void (*mqtt_incoming_publish_cb_t)(void *arg, const char *topic, u32_t tot_len);
138
139
140/**
141 * @ingroup mqtt
142 * Function prototype for mqtt request callback. Called when a subscribe, unsubscribe
143 * or publish request has completed
144 * @param arg Pointer to user data supplied when invoking request
145 * @param err ERR_OK on success
146 *            ERR_TIMEOUT if no response was received within timeout,
147 *            ERR_ABRT if (un)subscribe was denied
148 */
149typedef void (*mqtt_request_cb_t)(void *arg, err_t err);
150
151
152/**
153 * Pending request item, binds application callback to pending server requests
154 */
155struct mqtt_request_t
156{
157  /** Next item in list, NULL means this is the last in chain,
158      next pointing at itself means request is unallocated */
159  struct mqtt_request_t *next;
160  /** Callback to upper layer */
161  mqtt_request_cb_t cb;
162  void *arg;
163  /** MQTT packet identifier */
164  u16_t pkt_id;
165  /** Expire time relative to element before this  */
166  u16_t timeout_diff;
167};
168
169/** Ring buffer */
170struct mqtt_ringbuf_t {
171  u16_t put;
172  u16_t get;
173  u8_t buf[MQTT_OUTPUT_RINGBUF_SIZE];
174};
175
176/** MQTT client */
177struct mqtt_client_t
178{
179  /** Timers and timeouts */
180  u16_t cyclic_tick;
181  u16_t keep_alive;
182  u16_t server_watchdog;
183  /** Packet identifier generator*/
184  u16_t pkt_id_seq;
185  /** Packet identifier of pending incoming publish */
186  u16_t inpub_pkt_id;
187  /** Connection state */
188  u8_t conn_state;
189  struct tcp_pcb *conn;
190  /** Connection callback */
191  void *connect_arg;
192  mqtt_connection_cb_t connect_cb;
193  /** Pending requests to server */
194  struct mqtt_request_t *pend_req_queue;
195  struct mqtt_request_t req_list[MQTT_REQ_MAX_IN_FLIGHT];
196  void *inpub_arg;
197  /** Incoming data callback */
198  mqtt_incoming_data_cb_t data_cb;
199  mqtt_incoming_publish_cb_t pub_cb;
200  /** Input */
201  u32_t msg_idx;
202  u8_t rx_buffer[MQTT_VAR_HEADER_BUFFER_LEN];
203  /** Output ring-buffer */
204  struct mqtt_ringbuf_t output;
205};
206
207
208/** Connect to server */
209err_t mqtt_client_connect(mqtt_client_t *client, const ip_addr_t *ipaddr, u16_t port, mqtt_connection_cb_t cb, void *arg,
210                   const struct mqtt_connect_client_info_t *client_info);
211
212/** Disconnect from server */
213void mqtt_disconnect(mqtt_client_t *client);
214
215/** Create new client */
216mqtt_client_t *mqtt_client_new(void);
217
218/** Check connection status */
219u8_t mqtt_client_is_connected(mqtt_client_t *client);
220
221/** Set callback to call for incoming publish */
222void mqtt_set_inpub_callback(mqtt_client_t *client, mqtt_incoming_publish_cb_t,
223                             mqtt_incoming_data_cb_t data_cb, void *arg);
224
225/** Common function for subscribe and unsubscribe */
226err_t mqtt_sub_unsub(mqtt_client_t *client, const char *topic, u8_t qos, mqtt_request_cb_t cb, void *arg, u8_t sub);
227
228/** @ingroup mqtt
229 *Subscribe to topic */
230#define mqtt_subscribe(client, topic, qos, cb, arg) mqtt_sub_unsub(client, topic, qos, cb, arg, 1)
231/** @ingroup mqtt
232 *  Unsubscribe to topic */
233#define mqtt_unsubscribe(client, topic, cb, arg) mqtt_sub_unsub(client, topic, 0, cb, arg, 0)
234
235
236/** Publish data to topic */
237err_t mqtt_publish(mqtt_client_t *client, const char *topic, const void *payload, u16_t payload_length, u8_t qos, u8_t retain,
238                                    mqtt_request_cb_t cb, void *arg);
239
240#ifdef __cplusplus
241}
242#endif
243
244#endif /* LWIP_HDR_APPS_MQTT_CLIENT_H */
245