]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Demo/FreeRTOS_IoT_Libraries/mqtt/DemoTasks/SimpleMQTTExamples.c
Add first draft of mqtt example
[freertos] / FreeRTOS-Plus / Demo / FreeRTOS_IoT_Libraries / mqtt / DemoTasks / SimpleMQTTExamples.c
1 /*\r
2  * FreeRTOS Kernel V10.2.1\r
3  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://www.FreeRTOS.org\r
23  * http://aws.amazon.com/freertos\r
24  *\r
25  * 1 tab == 4 spaces!\r
26  */\r
27 \r
28 /* Standard inclues. */\r
29 #include <string.h>\r
30 \r
31 /* Kernel includes. */\r
32 #include "FreeRTOS.h"\r
33 #include "task.h"\r
34 \r
35 /* MQTT include. */\r
36 #include "iot_mqtt.h"\r
37 \r
38 /* Platform FreeRTOS network include. */\r
39 #include "platform/iot_network_freertos.h"\r
40 \r
41 /**\r
42  * @brief The keep-alive interval used for this example.\r
43  *\r
44  * An MQTT ping request will be sent periodically at this interval.\r
45  */\r
46 #define mqttexampleKEEP_ALIVE_SECONDS           ( 60 )\r
47 \r
48 /**\r
49  * @brief The timeout for MQTT operations in this example.\r
50  */\r
51 #define mqttexampleMQTT_TIMEOUT_MS                      ( 5000 )\r
52 \r
53 /**\r
54  * @brief The MQTT client identifier used in this example.\r
55  */\r
56 #define mqttexampleCLIENT_IDENTIFIER            "mqttexampleclient"\r
57 \r
58 /**\r
59  * @brief Details of the MQTT broker to connect to.\r
60  *\r
61  * @note This example does not use TLS and therefore won't work with AWS IoT.\r
62  */\r
63 #define mqttexampleMQTT_BROKER_ENDPOINT         "10.60.214.105"\r
64 #define mqttexampleMQTT_BROKER_PORT                     1883\r
65 \r
66 /**\r
67  * @brief The topic to subscribe and publish to in the example.\r
68  */\r
69 #define mqttexampleTOPIC                                        "example/topic"\r
70 \r
71 /**\r
72  * @brief The MQTT message published in this example.\r
73  */\r
74 #define mqttexampleMESSAGE                                      "Hello World!"\r
75 \r
76 /**\r
77  * @brief Paramters to control the retry behaviour in case a QoS1 publish\r
78  * message gets lost.\r
79  *\r
80  * Retry every minutes up to a maximum of 5 retries.\r
81  */\r
82 #define mqttexamplePUBLISH_RETRY_MS                     ( 1000 )\r
83 #define mqttexamplePUBLISH_RETRY_LIMIT          ( 5 )\r
84 \r
85 /**\r
86  * @brief The bit which is set in the demo task's notification value from the\r
87  * disconnect callback to inform the demo task about the MQTT disconnect.\r
88  */\r
89 #define mqttexampleDISCONNECTED_BIT                     ( 1UL << 0UL )\r
90 \r
91 /**\r
92  * @brief The bit which is set in the demo task's notification value from the\r
93  * publish callback to inform the demo task about the message received from the\r
94  * MQTT broker.\r
95  */\r
96 #define mqttexampleMESSAGE_RECEIVED_BIT         ( 1UL << 1UL )\r
97 /*-----------------------------------------------------------*/\r
98 \r
99 /**\r
100  * @brief The MQTT connection handle used in this example.\r
101  */\r
102 static IotMqttConnection_t xMQTTConnection = IOT_MQTT_CONNECTION_INITIALIZER;\r
103 /*-----------------------------------------------------------*/\r
104 \r
105 /**\r
106  * @brief The task used to demonstrate the MQTT API.\r
107  *\r
108  * @param[in] pvParameters Parmaters as passed at the time of task creation. Not\r
109  * used in this example.\r
110  */\r
111 static void prvMQTTDemoTask( void *pvParameters );\r
112 \r
113 /**\r
114  * @brief The callback invoked by the MQTT library when the MQTT connection gets\r
115  * disconnected.\r
116  * \r
117  * @param[in] pvCallbackContext Callback context as provided at the time of\r
118  * connect.\r
119  * @param[in] pxCallbackParams Contains the reason why the MQTT connection was\r
120  * disconnected.\r
121  */\r
122 static void prvExample_DisconnectCallback( void * pvCallbackContext,\r
123                                                                                    IotMqttCallbackParam_t * pxCallbackParams );\r
124 \r
125 /**\r
126  * @brief The callback invoked by the MQTT library when a message is received on\r
127  * a subscribed topic from the MQTT broker.\r
128  * \r
129  * @param[in] pvCallbackContext Callback context as provided at the time of\r
130  * subscribe.\r
131  * @param[in] pxCallbackParams Contain the details about the received message - \r
132  * topic on which the message was received, the received message.\r
133  */\r
134 static void prvExample_PublishCallback( void * pvCallbackContext,\r
135                                                                                 IotMqttCallbackParam_t * pxCallbackParams );\r
136 \r
137 /**\r
138  * @brief Connects to the MQTT broker as specified in mqttexampleMQTT_BROKER_ENDPOINT\r
139  * and mqttexampleMQTT_BROKER_PORT.\r
140  * \r
141  * @note This example does not use TLS and therefore will not work with MQTT.\r
142  */\r
143 static void prvMQTTConnect( void );\r
144 \r
145 /**\r
146  * @brief Subscribes to the topic as specified in mqttexampleTOPIC.\r
147  */\r
148 static void prvMQTTSubscribe( void );\r
149 \r
150 /**\r
151  * @brief Publishes a messages mqttexampleMESSAGE on mqttexampleTOPIC topic.\r
152  */\r
153 static void prvMQTTPublish( void );\r
154 \r
155 /**\r
156  * @brief Unsubscribes from the mqttexampleTOPIC topic.\r
157  */\r
158 static void prvMQTTUnsubscribe( void );\r
159 \r
160 /**\r
161  * @brief Disconnects from the MQTT broker gracefully by sending an MQTT\r
162  * DISCONNECT message.\r
163  */\r
164 static void prvMQTTDisconnect( void );\r
165 /*-----------------------------------------------------------*/\r
166 \r
167 static void prvExample_DisconnectCallback( void * pvCallbackContext,\r
168                                                                                    IotMqttCallbackParam_t * pxCallbackParams )\r
169 {\r
170 TaskHandle_t xDemoTaskHandle = ( TaskHandle_t ) pvCallbackContext;\r
171 \r
172         /* Ensure that we initiated the disconnect. */\r
173         configASSERT( pxCallbackParams->u.disconnectReason == IOT_MQTT_DISCONNECT_CALLED );\r
174 \r
175         /* Inform the demo task about the disconnect. */\r
176         xTaskNotify( xDemoTaskHandle,\r
177                                 mqttexampleDISCONNECTED_BIT,\r
178                                 eSetBits /* Set the mqttexampleDISCONNECTED_BIT in the demo task's notification value. */\r
179                                 );\r
180 }\r
181 /*-----------------------------------------------------------*/\r
182 \r
183 static void prvExample_PublishCallback( void * pvCallbackContext,\r
184                                                                                 IotMqttCallbackParam_t * pxCallbackParams )\r
185 {\r
186 TaskHandle_t xDemoTaskHandle = ( TaskHandle_t ) pvCallbackContext;\r
187 \r
188         /* Ensure that the message is received on the expected topic. */\r
189         configASSERT( pxCallbackParams->u.message.info.topicNameLength == strlen( mqttexampleTOPIC ) );\r
190         configASSERT( strncmp( pxCallbackParams->u.message.info.pTopicName,\r
191                                                    mqttexampleTOPIC,\r
192                                                    strlen( mqttexampleTOPIC ) ) == 0 );\r
193 \r
194         /* Ensure that the expected message is received. */\r
195         configASSERT( pxCallbackParams->u.message.info.payloadLength == strlen( mqttexampleMESSAGE ) );\r
196         configASSERT( strncmp( pxCallbackParams->u.message.info.pPayload,\r
197                                                    mqttexampleMESSAGE,\r
198                                                    strlen( mqttexampleMESSAGE ) ) == 0 );\r
199 \r
200         /* Ensure that the message QoS is as expected. */\r
201         configASSERT( pxCallbackParams->u.message.info.qos == IOT_MQTT_QOS_1 );\r
202 \r
203         /* Inform the demo task about the message received from the MQTT broker. */\r
204         xTaskNotify( xDemoTaskHandle,\r
205                                 mqttexampleMESSAGE_RECEIVED_BIT,\r
206                                 eSetBits /* Set the mqttexampleMESSAGE_RECEIVED_BIT in the demo task's notification value. */\r
207                                 );\r
208 }\r
209 /*-----------------------------------------------------------*/\r
210 \r
211 void vStartSimpleMQTTDemo( void )\r
212 {\r
213         /* This example uses a single application task, which in turn is used to\r
214          * connect, subscribe, publish, unsubscribe and disconnect from the MQTT\r
215          * broker. */\r
216         xTaskCreate( prvMQTTDemoTask,                   /* Function that implements the task. */\r
217                                  "MQTTDemo",                            /* Text name for the task - only used for debugging. */\r
218                                  configMINIMAL_STACK_SIZE,      /* Size of stack (in words, not bytes) to allocate for the task. */\r
219                                  NULL,                                          /* Task parameter - not used in this case. */\r
220                                  tskIDLE_PRIORITY,                      /* Task priority, must be between 0 and configMAX_PRIORITIES - 1. */\r
221                                  NULL );                                        /* Used to pass out a handle to the created task - not used in this case. */\r
222 }\r
223 /*-----------------------------------------------------------*/\r
224 \r
225 static void prvMQTTDemoTask( void *pvParameters )\r
226 {\r
227 IotMqttError_t xResult;\r
228 uint32_t ulNotificationValue = 0;\r
229 const TickType_t xNoDelay = ( TickType_t ) 0;\r
230 \r
231         /* Remove compiler warnings about unused parameters. */\r
232         ( void ) pvParameters;\r
233 \r
234         /* MQTT library must be initialized before it can be used. This is just one\r
235          * time initialization. */\r
236         xResult = IotMqtt_Init();\r
237         configASSERT( xResult == IOT_MQTT_SUCCESS );\r
238 \r
239         for( ; ; )\r
240         {\r
241                 /* Don't expect any notifications to be pending yet. */\r
242                 configASSERT( ulTaskNotifyTake( pdTRUE, xNoDelay ) == 0 );\r
243 \r
244                 /* Establish a connection to the MQTT broker. This example connects to\r
245                  * the MQTT broker as specified in mqttexampleMQTT_BROKER_ENDPOINT and\r
246                  * mqttexampleMQTT_BROKER_PORT at the top of this file. Please change\r
247                  * it to the MQTT broker you want to connect to. Note that this example\r
248                  * does not use TLS and therefore will not work with AWS IoT. */\r
249                 prvMQTTConnect();\r
250 \r
251                 /* Subscribe to the topic as specified in mqttexampleTOPIC at the top\r
252                  * of this file. */\r
253                 prvMQTTSubscribe();\r
254 \r
255                 /* Publish a message on the mqttexampleTOPIC topic as specified at the\r
256                  * top of this file. */\r
257                 prvMQTTPublish();\r
258 \r
259                 /* Since we are subscribed on the same topic, we will get the same\r
260                  * message back from the MQTT broker. Wait for the message to be\r
261                  * received which is informed to us by the publish callback\r
262                  * (prvExample_PublishCallback) by setting the mqttexampleMESSAGE_RECEIVED_BIT\r
263                  * in this task's notification value. */\r
264                 xTaskNotifyWait( 0UL, /* Don't clear any bits on entry. */\r
265                                                  0UL, /* Don't clear any bits on exit. */\r
266                                                  &( ulNotificationValue ), /* Obtain the notification value. */\r
267                                                  pdMS_TO_TICKS( mqttexampleMQTT_TIMEOUT_MS ) );\r
268                 configASSERT( ( ulNotificationValue & mqttexampleMESSAGE_RECEIVED_BIT ) == mqttexampleMESSAGE_RECEIVED_BIT );\r
269 \r
270                 /* Unsubscribe from the topic mqttexampleTOPIC. */\r
271                 prvMQTTUnsubscribe();\r
272 \r
273                 /* Gracefully disconnect from the MQTT broker by sending an MQTT\r
274                  * DISCONNECT message. */\r
275                 prvMQTTDisconnect();\r
276 \r
277                 /* Wait for the disconnect operation to complete which is informed to us\r
278                  * by the disconnect callback (prvExample_DisconnectCallback)by setting\r
279                  * the mqttexampleDISCONNECTED_BIT in this task's notification value.\r
280                  * Note that all bits are cleared in the task's notification value to\r
281                  * ensure that it is ready for the next run. */\r
282                 xTaskNotifyWait( 0UL, /* Don't clear any bits on entry. */\r
283                                                  portMAX_DELAY, /* Clear all bits on exit - portMAX_DELAY is used as it is a portable way of having all bits set. */\r
284                                                  &( ulNotificationValue ), /* Obtain the notification value. */\r
285                                                  pdMS_TO_TICKS( mqttexampleMQTT_TIMEOUT_MS ) );\r
286                 configASSERT( ( ulNotificationValue & mqttexampleDISCONNECTED_BIT ) == mqttexampleDISCONNECTED_BIT );\r
287         }\r
288 }\r
289 /*-----------------------------------------------------------*/\r
290 \r
291 static void prvMQTTConnect( void )\r
292 {\r
293 IotMqttError_t xResult;\r
294 IotNetworkServerInfo_t xMQTTBrokerInfo;\r
295 IotMqttNetworkInfo_t xNetworkInfo = IOT_MQTT_NETWORK_INFO_INITIALIZER;\r
296 IotMqttConnectInfo_t xConnectInfo = IOT_MQTT_CONNECT_INFO_INITIALIZER;\r
297 \r
298         /******************* Broker information setup. **********************/\r
299         xMQTTBrokerInfo.pHostName = mqttexampleMQTT_BROKER_ENDPOINT;\r
300         xMQTTBrokerInfo.port = mqttexampleMQTT_BROKER_PORT;\r
301 \r
302         /******************* Network information setup. **********************/\r
303         /* No connection to the MQTT broker has been established yet and we want to\r
304          * establish a new connection. */\r
305         xNetworkInfo.createNetworkConnection = true;\r
306         xNetworkInfo.u.setup.pNetworkServerInfo = &( xMQTTBrokerInfo );\r
307 \r
308         /* This example does not use TLS and therefore pNetworkCredentialInfo must\r
309          * be set to NULL. */\r
310         xNetworkInfo.u.setup.pNetworkCredentialInfo = NULL;\r
311 \r
312         /* Use FreeRTOS+TCP network. */\r
313         xNetworkInfo.pNetworkInterface = IOT_NETWORK_INTERFACE_AFR;\r
314 \r
315         /* Setup the callback which is called when the MQTT connection is disconnected. */\r
316         xNetworkInfo.disconnectCallback.pCallbackContext = ( void * ) xTaskGetCurrentTaskHandle();\r
317         xNetworkInfo.disconnectCallback.function = prvExample_DisconnectCallback;\r
318 \r
319         /****************** MQTT Connection information setup. ********************/\r
320         /* This example does not use TLS and therefore won't work with AWS IoT. */\r
321         xConnectInfo.awsIotMqttMode = false;\r
322 \r
323         /* Start with a clean session i.e. direct the MQTT broker to discard any\r
324          * previous session data. Also, establishing a connection with clean session\r
325          * will ensure that the broker does not store any data when this client\r
326          * gets disconnected. */\r
327         xConnectInfo.cleanSession = true;\r
328 \r
329         /* Since we are starting with a clean session, there are no previous\r
330          * subscriptions to be restored. */\r
331         xConnectInfo.pPreviousSubscriptions = NULL;\r
332         xConnectInfo.previousSubscriptionCount = 0;\r
333 \r
334         /* We do not want to publish Last Will and Testament (LWT) message if the\r
335          * client gets disconnected. */\r
336         xConnectInfo.pWillInfo = NULL;\r
337 \r
338         /* Send an MQTT PING request every minute. */\r
339         xConnectInfo.keepAliveSeconds = mqttexampleKEEP_ALIVE_SECONDS;\r
340 \r
341         /* The client identifier is used to uniquely identify this MQTT client to\r
342          * the MQTT broker. */\r
343         xConnectInfo.pClientIdentifier = mqttexampleCLIENT_IDENTIFIER;\r
344         xConnectInfo.clientIdentifierLength = ( uint16_t ) strlen( mqttexampleCLIENT_IDENTIFIER );\r
345 \r
346         /* This example does not use any authentication and therefore username and\r
347          * password fields are not used. */\r
348         xConnectInfo.pUserName = NULL;\r
349         xConnectInfo.userNameLength = 0;\r
350         xConnectInfo.pPassword = NULL;\r
351         xConnectInfo.passwordLength = 0;\r
352 \r
353         /* Establish the connection to the MQTT broker - It is a blocking call and\r
354         will return only when connection is complete. */\r
355         xResult = IotMqtt_Connect( &( xNetworkInfo ),\r
356                                                            &( xConnectInfo ),\r
357                                                            mqttexampleMQTT_TIMEOUT_MS,\r
358                                                            &( xMQTTConnection ) );\r
359         configASSERT( xResult == IOT_MQTT_SUCCESS );\r
360 }\r
361 /*-----------------------------------------------------------*/\r
362 \r
363 static void prvMQTTSubscribe( void )\r
364 {\r
365 IotMqttError_t xResult;\r
366 IotMqttSubscription_t xMQTTSubscription;\r
367 \r
368         /* Subscribe to the mqttexampleTOPIC topic filter. */\r
369         xMQTTSubscription.qos = IOT_MQTT_QOS_1;\r
370         xMQTTSubscription.pTopicFilter = mqttexampleTOPIC;\r
371         xMQTTSubscription.topicFilterLength = ( uint16_t ) strlen( mqttexampleTOPIC );\r
372         xMQTTSubscription.callback.pCallbackContext = ( void * ) xTaskGetCurrentTaskHandle();\r
373         xMQTTSubscription.callback.function = prvExample_PublishCallback;\r
374 \r
375         /* Use the synchronous API to subscribe - It is a blocking call and only\r
376          * returns when the subscribe operation is complete. */\r
377         xResult = IotMqtt_TimedSubscribe( xMQTTConnection,\r
378                                                                           &( xMQTTSubscription ),\r
379                                                                           1, /* We are subscribing to one topic filter. */\r
380                                                                           0, /* flags - currently ignored. */\r
381                                                                           mqttexampleMQTT_TIMEOUT_MS );\r
382         configASSERT( xResult == IOT_MQTT_SUCCESS );\r
383 }\r
384 /*-----------------------------------------------------------*/\r
385 \r
386 static void prvMQTTPublish( void )\r
387 {\r
388 IotMqttError_t xResult;\r
389 IotMqttPublishInfo_t xMQTTPublishInfo;\r
390 \r
391         /* Publish a message with QoS1 on the mqttexampleTOPIC topic. Since we are\r
392          * subscribed to the same topic, the MQTT broker will send the same message\r
393          * back to us. It is verified in the publish callback. */\r
394         xMQTTPublishInfo.qos = IOT_MQTT_QOS_1;\r
395         xMQTTPublishInfo.retain = false;\r
396         xMQTTPublishInfo.pTopicName = mqttexampleTOPIC;\r
397         xMQTTPublishInfo.topicNameLength = ( uint16_t ) strlen( mqttexampleTOPIC );\r
398         xMQTTPublishInfo.pPayload = mqttexampleMESSAGE;\r
399         xMQTTPublishInfo.payloadLength = strlen( mqttexampleMESSAGE );\r
400         xMQTTPublishInfo.retryMs = mqttexamplePUBLISH_RETRY_MS;\r
401         xMQTTPublishInfo.retryLimit = mqttexamplePUBLISH_RETRY_LIMIT;\r
402 \r
403         /* Use the synchronous API to publish - It is a blocking call and only\r
404          * returns when the publish operation is complete. */\r
405         xResult = IotMqtt_TimedPublish( xMQTTConnection,\r
406                                                                         &( xMQTTPublishInfo ),\r
407                                                                         0, /* flags - currently ignored. */\r
408                                                                         mqttexampleMQTT_TIMEOUT_MS );\r
409         configASSERT( xResult == IOT_MQTT_SUCCESS );\r
410 }\r
411 /*-----------------------------------------------------------*/\r
412 \r
413 static void prvMQTTUnsubscribe( void )\r
414 {\r
415 IotMqttError_t xResult;\r
416 IotMqttSubscription_t xMQTTSubscription;\r
417 \r
418         /* Unsubscribe from the mqttexampleTOPIC topic filter. */\r
419         xMQTTSubscription.pTopicFilter = mqttexampleTOPIC;\r
420         xMQTTSubscription.topicFilterLength = ( uint16_t ) strlen( mqttexampleTOPIC );\r
421         /* The following members of the IotMqttSubscription_t are ignored by the\r
422          * unsubscribe operation. Just initialize them to avoid "use of uninitialized\r
423          * variable" warnings. */\r
424         xMQTTSubscription.qos = IOT_MQTT_QOS_1;\r
425         xMQTTSubscription.callback.pCallbackContext = NULL;\r
426         xMQTTSubscription.callback.function = NULL;\r
427 \r
428         /* Use the synchronous API to unsubscribe - It is a blocking call and only\r
429          * returns when the unsubscribe operation is complete. */\r
430         xResult = IotMqtt_TimedUnsubscribe( xMQTTConnection,\r
431                                                                                 &( xMQTTSubscription ),\r
432                                                                                 1, /* We are unsubscribing from one topic filter. */\r
433                                                                                 0, /* flags - currently ignored. */\r
434                                                                                 mqttexampleMQTT_TIMEOUT_MS );\r
435         configASSERT( xResult == IOT_MQTT_SUCCESS );\r
436 }\r
437 /*-----------------------------------------------------------*/\r
438 \r
439 static void prvMQTTDisconnect( void )\r
440 {\r
441         /* Send a MQTT DISCONNECT packet to the MQTT broker to do a graceful\r
442          * disconnect. */\r
443         IotMqtt_Disconnect( xMQTTConnection,\r
444                                                 0 /* flags - 0 means a graceful disconnect by sending MQTT DISCONNECT. */\r
445                                                 );\r
446 }\r
447 /*-----------------------------------------------------------*/\r