]> git.sur5r.net Git - freertos/blob - FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/DemoTasks/ShadowDeviceOperationsExamples.c
25b7d77a539d00732d4fcefb07fb77923a7f3700
[freertos] / FreeRTOS-Labs / Demo / FreeRTOS_IoT_Libraries / shadow / shadow_device_operations / DemoTasks / ShadowDeviceOperationsExamples.c
1 /*\r
2  * FreeRTOS Kernel V10.3.0\r
3  * Copyright (C) 2020 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 /* A device's Shadow is a JSON document that is used to store and retrieve\r
29  * current state information for a device in AWS (Amazon Web Services) Cloud.\r
30  * Please refer to the AWS documentation for more details about Device Shadow\r
31  * service.\r
32  * https://docs.aws.amazon.com/iot/latest/developerguide/iot-device-shadows.html\r
33  *\r
34  * This demo creates a single application task that loops through a set of\r
35  * examples that demonstrates usage of Shadow library. Please find the list of\r
36  * Shadow operations and callbacks used in this demo below.\r
37  * Shadow Delete           - Deletes the Shadow document of the device.\r
38  * Shadow Update           - Updates the Shadow document with JSON document\r
39  *                           provided.\r
40  * Shadow Delta Callback   - Callback to be invoked when Shadow document is\r
41  *                           updated with different desired and reported\r
42  *                           states.\r
43  * Shadow Updated Callback - Callback to be invoked when a Shadow document is\r
44  *                           updated.\r
45  *\r
46  * The demo program uses Shadow Update and Shadow Delta Callbacks to simulate\r
47  * toggling a remote device's state. It sends a Shadow Update with a new\r
48  * desired state and waits for the device to change its reported state in\r
49  * Shadow Delta Callback as a response to the new desired state. In addition,\r
50  * a Shadow Updated Callback is used to print the changing Shadow states.\r
51  * Shadow Updates are done #shadowexampleUPDATE_COUNT times in each loop.At the\r
52  * end of each loop Shadow document is deleted using Shadow Delete.\r
53  *\r
54  * In this demo both update to the desired state of Shadow document and\r
55  * response to it by updating the reported state is done in the same\r
56  * application. This is to illustrate the capability of the Shadow service and\r
57  * library in a single demo. Ideally the update to the desired state can be\r
58  * from an external application to control the state of the device. This demo\r
59  * is meant to demonstrate the usage of different Shadow library APIs.\r
60  *\r
61  * The Shadow demo uses a MQTT connection to connect to Shadow Service in AWS.\r
62  * Mutual authentication between AWS IoT MQTT Broker and Device is required to\r
63  * run this demo. Please complete configurations in aws_iot_demo_profile.h for\r
64  * mutual authentication.\r
65  * More details for mutual authentication configuration can be found at\r
66  * https://www.freertos.org/mqtt/preconfiguredexamplesMA.html\r
67  *\r
68  * Note: The parser used in this demo is specific for parsing AWS IoT document\r
69  * received through a mutually authenticated connection with AWS IoT MQTT\r
70  * broker. This parser will not check for the correctness of the document as it\r
71  * is designed for low memory footprint rather than checking for correctness of\r
72  * the JSON document. This parser is not meant to be used as a general purpose\r
73  * JSON parser.\r
74  */\r
75 \r
76 /* Standard includes. */\r
77 #include <string.h>\r
78 #include <stdio.h>\r
79 \r
80 /* Kernel includes. */\r
81 #include "FreeRTOS.h"\r
82 #include "task.h"\r
83 #include "semphr.h"\r
84 \r
85 /* FreeRTOS+TCP includes. */\r
86 #include "FreeRTOS_IP.h"\r
87 \r
88 /* IoT SDK includes. */\r
89 #include "aws_iot_shadow.h"\r
90 #include "aws_iot_demo_profile.h"\r
91 #include "iot_mqtt.h"\r
92 #include "iot_taskpool_freertos.h"\r
93 #include "aws_iot_doc_parser.h"\r
94 #include "platform/iot_clock.h"\r
95 #include "platform/iot_threads.h"\r
96 #include "platform/iot_network_freertos.h"\r
97 \r
98 /* Preprocessor check iot configuration */\r
99 #include "aws_iot_setup_check.h"\r
100 \r
101 /* Demo specific includes. */\r
102 #include "demo_config.h"\r
103 \r
104 /**\r
105  * @brief The keep-alive interval used for this example.\r
106  *\r
107  * An MQTT ping request will be sent periodically at this interval.\r
108  *\r
109  * @note: This value is set to zero to disable MQTT\r
110  * keep alive for the Windows simulator project.\r
111  * The FreeRTOS kernel does not accurately calculate time for the Windows\r
112  * Simulator. Therefore, MQTT PING Request messages may be sent\r
113  * at an incorrect time interval to the broker. If the broker does\r
114  * not receive a ping request within 1.5x the time sent in a\r
115  * connection request, the broker may close the connection.\r
116  * To enable the keep alive feature, set this value\r
117  * to the desired interval in seconds.\r
118  */\r
119 #define shadowexampleKEEP_ALIVE_SECONDS            ( 0 )\r
120 \r
121 /**\r
122  * @brief The timeout for MQTT operations in this example.\r
123  */\r
124 #define shadowexampleMQTT_TIMEOUT_MS                     ( 5000 )\r
125 \r
126 /**\r
127  * @brief Update count of shadow in a loop in the demo.\r
128  *\r
129  */\r
130 #define shadowexampleUPDATE_COUNT                                ( 20 )\r
131 \r
132 /**\r
133  * @brief The task wait period between each Shadow update.\r
134  *\r
135  */\r
136 #define shadowexampleUPDATE_PERIOD_MS                    ( 3000 )\r
137 \r
138 /**\r
139  * @brief The task wait period between each demo loop.\r
140  */\r
141 #define shadowexampleLOOP_WAIT_PERIOD_MS                 ( 5000 )\r
142 \r
143 /**\r
144  * @brief The timeout period for updates from Shadow Delta Callback before\r
145  * attempting next Shadow Update.\r
146  */\r
147 #define shadowexampleWAIT_PERIOD_FOR_DELTA_MS    ( 5000 )\r
148 \r
149 /**\r
150  * @brief Argument for AwsIotShadow_Init to use the default timeout.\r
151  */\r
152 #define shadowexampleUSE_DEFAULT_MQTT_TIMEOUT    ( 0 )\r
153 \r
154 /**\r
155  * @brief The bit which is set in the demo task's notification value from the\r
156  * disconnect callback to inform the demo task about the MQTT disconnect.\r
157  */\r
158 #define shadowexampleDISCONNECTED_BIT                    ( 1UL << 0UL )\r
159 \r
160 /**\r
161  * @brief Compile time calculation of shadowexampleCLIENT_IDENTIFIER_LENGTH.\r
162  */\r
163 #define shadowexampleCLIENT_IDENTIFIER_LENGTH    sizeof( awsiotdemoprofileCLIENT_IDENTIFIER ) - 1\r
164 \r
165 /**\r
166  * @brief Format string representing a Shadow document with a "desired" state.\r
167  *\r
168  * Note the client token, which is required for all Shadow updates. The client\r
169  * token must be unique at any given time, but may be reused once the update is\r
170  * completed. For this demo, a timestamp is used for a client token.\r
171  */\r
172 #define shadowexampleDESIRED_JSON \\r
173         "{"                                                       \\r
174         "\"state\":{"                             \\r
175         "\"desired\":{"                           \\r
176         "\"powerOn\":%01d"                        \\r
177         "}"                                                       \\r
178         "},"                                              \\r
179         "\"clientToken\":\"%06lu\""       \\r
180         "}"\r
181 \r
182 /**\r
183  * @brief The expected size of #shadowexampleDESIRED_JSON.\r
184  *\r
185  * Because all the format specifiers in #shadowexampleDESIRED_JSON include a\r
186  * length, its full size is known at compile-time.\r
187  */\r
188 #define shadowexampleDESIRED_JSON_SIZE    ( sizeof( shadowexampleDESIRED_JSON ) - 3 )\r
189 \r
190 /**\r
191  * @brief Format string representing a Shadow document with a "reported" state.\r
192  *\r
193  * Note the client token, which is required for all Shadow updates. The client\r
194  * token must be unique at any given time, but may be reused once the update is\r
195  * completed. For this demo, a timestamp is used for a client token.\r
196  */\r
197 #define shadowexampleREPORTED_JSON \\r
198         "{"                                                        \\r
199         "\"state\":{"                              \\r
200         "\"reported\":{"                           \\r
201         "\"powerOn\":%01d"                         \\r
202         "}"                                                        \\r
203         "},"                                               \\r
204         "\"clientToken\":\"%06lu\""        \\r
205         "}"\r
206 \r
207 /**\r
208  * @brief The expected size of #shadowexampleREPORTED_JSON.\r
209  *\r
210  * Because all the format specifiers in #shadowexampleREPORTED_JSON include a\r
211  * length, its full size is known at compile-time.\r
212  */\r
213 #define shadowexampleREPORTED_JSON_SIZE    ( sizeof( shadowexampleREPORTED_JSON ) - 3 )\r
214 \r
215 /**\r
216 *  @brief This is the current state of the shadow used in this demo.\r
217 */\r
218 static int32_t lDevicePowerOnState = 0;\r
219 \r
220 /**\r
221  * @brief This is a Semaphore used to synchronize between delta callback and\r
222  * Shadow updates.\r
223  */\r
224 iot_sem_internal_t xDeltaSemaphore = { 0 };\r
225 \r
226 /**\r
227  * @brief The task used to demonstrate Shadow.\r
228  *\r
229  * @param[in] pvParameters Parameters as passed at the time of task creation. Not\r
230  * used in this example.\r
231  *\r
232  */\r
233 static void prvShadowDemoTask( void *pvParameters );\r
234 \r
235 /**\r
236  * @brief The callback invoked by the MQTT library when the MQTT connection gets\r
237  * disconnected.\r
238  *\r
239  * @param[in] pvCallbackContext Callback context as provided at the time of\r
240  * connect.\r
241  * @param[in] pxCallbackParams Contains the reason why the MQTT connection was\r
242  * disconnected.\r
243  */\r
244 static void prvExample_OnDisconnect( void * pvCallbackContext,\r
245                                                                          IotMqttCallbackParam_t * pxCallbackParams );\r
246 \r
247 /**\r
248  * @brief The callback invoked by the MQTT library when a message is received on\r
249  * a subscribed topic from the MQTT broker.\r
250  *\r
251  * @param[in] pvCallbackContext Callback context as provided at the time of\r
252  * subscribe.\r
253  * @param[in] pxCallbackParams Contain the details about the received message -\r
254  * topic on which the message was received, the received message.\r
255  */\r
256 static void prvExample_OnMessageReceived( void * pvCallbackContext,\r
257                                                                                   IotMqttCallbackParam_t * pxCallbackParams );\r
258 \r
259 /**\r
260  * @brief Connects to the MQTT broker as specified in awsiotdemoprofileAWS_ENDPOINT\r
261  * and awsiotdemoprofileAWS_MQTT_PORT.\r
262  *\r
263  */\r
264 static void prvMQTTConnect( void );\r
265 \r
266 /**\r
267  * @brief Disconnects from the MQTT broker gracefully by sending an MQTT\r
268  * DISCONNECT message.\r
269  *\r
270  */\r
271 static void prvMQTTDisconnect( void );\r
272 \r
273 /**\r
274 * @brief Initializes the IoT libraries used by this demo.\r
275 */\r
276 static void prvInitialiseLibraries( void );\r
277 \r
278 /**\r
279  * @brief The MQTT connection handle used in this example.\r
280  */\r
281 static IotMqttConnection_t xMQTTConnection = IOT_MQTT_CONNECTION_INITIALIZER;\r
282 \r
283 /**\r
284  * @brief Set the Shadow callback functions used in this demo.\r
285  *\r
286  * There are 2 Shadow callbacks set by this function. updated callback\r
287  * and delta Callback.\r
288  *\r
289  */\r
290 static void prvSetShadowCallbacks( void );\r
291 \r
292 /**\r
293  * @brief Clear the Shadow callbacks.\r
294  *\r
295  * There are 2 Shadow callbacks cleared by this function. updated callback\r
296  * and delta Callback.\r
297  *\r
298  */\r
299 static void prvClearShadowCallbacks( void );\r
300 \r
301 /**\r
302  * @brief Try to delete any Shadow document in the cloud.\r
303  *\r
304  */\r
305 static void prvClearShadowDocument( void );\r
306 \r
307 /**\r
308  * @brief Send the Shadow updates that will trigger the Shadow callbacks.\r
309  *\r
310  */\r
311 static void prvSendShadowUpdates( void );\r
312 \r
313 /**\r
314  * @brief Shadow delta callback, invoked when the desired and updates Shadow\r
315  * states differ.\r
316  *\r
317  * This function simulates a device updating its state in response to a Shadow.\r
318  *\r
319  * @param[in] pCallbackContext Delta semaphore used to synchronize between\r
320  * delta callback and updated callback.\r
321  * @param[in] pxCallbackParam The received Shadow delta document.\r
322  */\r
323 static void prvShadowDeltaCallback( void * pCallbackContext,\r
324                                                                         AwsIotShadowCallbackParam_t * pxCallbackParam );\r
325 \r
326 /**\r
327  * @brief Shadow updated callback, invoked when the Shadow document changes.\r
328  *\r
329  * This function reports when a Shadow has been updated.\r
330  *\r
331  * @param[in] pCallbackContext Not used.\r
332  * @param[in] pxCallbackParam The received Shadow updated document.\r
333  */\r
334 static void prvShadowUpdatedCallback( void * pCallbackContext,\r
335                                                                           AwsIotShadowCallbackParam_t * pxCallbackParam );\r
336 \r
337 /**\r
338  * @brief Parses a key in the "state" section of a Shadow delta document.\r
339  *\r
340  * @param[in] pcDeltaDocument The Shadow delta document to parse.\r
341  * @param[in] xDeltaDocumentLength The length of `pcDeltaDocument`.\r
342  * @param[in] pcDeltaKey The key in the delta document to find. Must be NULL-terminated.\r
343  * @param[out] ppcDelta Set to the first character in the delta key.\r
344  * @param[out] pxDeltaLength The length of the delta key.\r
345  *\r
346  * @return `true` if the given delta key is found; `false` otherwise.\r
347  */\r
348 static BaseType_t prvGetDelta( const char * pcDeltaDocument,\r
349                                                            size_t xDeltaDocumentLength,\r
350                                                            const char * pcDeltaKey,\r
351                                                            const char ** ppcDelta,\r
352                                                            size_t * pxDeltaLength );\r
353 \r
354 /**\r
355  * @brief Parses the "state" key from the "previous" or "current" sections of a\r
356  * Shadow updated document.\r
357  *\r
358  * @param[in] pcUpdatedDocument The Shadow updated document to parse.\r
359  * @param[in] xUpdatedDocumentLength The length of `pcUpdatedDocument`.\r
360  * @param[in] pcSectionKey Either "previous" or "current". Must be NULL-terminated.\r
361  * @param[out] ppcState Set to the first character in "state".\r
362  * @param[out] pxStateLength Length of the "state" section.\r
363  *\r
364  * @return pdTRUE if the "state" was found; pdFALSE otherwise.\r
365  */\r
366 static BaseType_t prvGetUpdatedState( const char * pcUpdatedDocument,\r
367                                                                           size_t xUpdatedDocumentLength,\r
368                                                                           const char * pcSectionKey,\r
369                                                                           const char ** ppcState,\r
370                                                                           size_t * pxStateLength );\r
371 \r
372 /*-----------------------------------------------------------*/\r
373 \r
374 /**\r
375  * @brief Parameters used to create the system task pool.\r
376  */\r
377 static const IotTaskPoolInfo_t xTaskPoolParameters =\r
378 {\r
379         /* Minimum number of threads in a task pool.\r
380          * Note the slimmed down version of the task\r
381          * pool used by this library does not auto-scale\r
382          * the number of tasks in the pool so in this\r
383          * case this sets the number of tasks in the\r
384          * pool. */\r
385         1,\r
386 \r
387         /* Maximum number of threads in a task pool.\r
388          * Note the slimmed down version of the task\r
389          * pool used by this library does not auto-scale\r
390          * the number of tasks in the pool so in this\r
391          * case this parameter is just ignored. */\r
392         1,\r
393 \r
394         /* Stack size for every task pool thread - in\r
395          * bytes, hence multiplying by the number of bytes\r
396          * in a word as configMINIMAL_STACK_SIZE is\r
397          * specified in words. */\r
398         configMINIMAL_STACK_SIZE * sizeof( portSTACK_TYPE ),\r
399         /* Priority for every task pool thread. */\r
400         tskIDLE_PRIORITY,\r
401 };\r
402 \r
403 /*-----------------------------------------------------------*/\r
404 \r
405 static const struct IotNetworkServerInfo xMQTTBrokerInfo =\r
406 {\r
407         .pHostName = awsiotdemoprofileAWS_ENDPOINT,\r
408         .port = awsiotdemoprofileAWS_MQTT_PORT\r
409 };\r
410 \r
411 static struct IotNetworkCredentials xNetworkSecurityCredentials =\r
412 {\r
413         /* Optional TLS extensions. For this demo, they are disabled. */\r
414         .pAlpnProtos = NULL,\r
415         .maxFragmentLength = 0,\r
416 \r
417         /* SNI is enabled by default. */\r
418         .disableSni = false,\r
419 \r
420         /* Provide the certificate for validating the server. Only required for\r
421         demos using TLS. */\r
422         .pRootCa = awsiotdemoprofileAWS_CERTIFICATE_PEM,\r
423         .rootCaSize = sizeof( awsiotdemoprofileAWS_CERTIFICATE_PEM ),\r
424 \r
425         /* Strong mutual authentication to authenticate both the broker and\r
426         * the client. */\r
427         .pClientCert = awsiotdemoprofileCLIENT_CERTIFICATE_PEM,\r
428         .clientCertSize = sizeof( awsiotdemoprofileCLIENT_CERTIFICATE_PEM ),\r
429         .pPrivateKey = awsiotdemoprofileCLIENT_PRIVATE_KEY_PEM,\r
430         .privateKeySize = sizeof( awsiotdemoprofileCLIENT_PRIVATE_KEY_PEM )\r
431 };\r
432 \r
433 static IotMqttNetworkInfo_t xNetworkInfo =\r
434 {\r
435         /* No connection to the MQTT broker has been established yet and we want to\r
436          * establish a new connection. */\r
437         .createNetworkConnection = true,\r
438         .u.setup.pNetworkServerInfo = &( xMQTTBrokerInfo ),\r
439 \r
440         /* Set the TLS credentials for the new MQTT connection. This member is NULL\r
441          * for the plain text MQTT demo. */\r
442         .u.setup.pNetworkCredentialInfo = &xNetworkSecurityCredentials,\r
443 \r
444         /* Use FreeRTOS+TCP network interface. */\r
445         .pNetworkInterface = IOT_NETWORK_INTERFACE_FREERTOS,\r
446 \r
447         /* Setup the callback which is called when the MQTT connection is\r
448          * disconnected. The task handle is passed as the callback context which\r
449          * is used by the callback to send a task notification to this task.*/\r
450         .disconnectCallback.function = prvExample_OnDisconnect\r
451 };\r
452 \r
453 \r
454 static const IotMqttConnectInfo_t xConnectInfo =\r
455 {\r
456         /* Set this flag to true if connecting to the AWS IoT MQTT broker. */\r
457         .awsIotMqttMode = true,\r
458 \r
459         /* Start with a clean session i.e. direct the MQTT broker to discard any\r
460          * previous session data. Also, establishing a connection with clean session\r
461          * will ensure that the broker does not store any data when this client\r
462          * gets disconnected. */\r
463         .cleanSession = true,\r
464 \r
465         /* Since we are starting with a clean session, there are no previous\r
466          * subscriptions to be restored. */\r
467         .pPreviousSubscriptions = NULL,\r
468         .previousSubscriptionCount = 0,\r
469 \r
470         /* We do not want to publish Last Will and Testament (LWT) message if the\r
471          * client gets disconnected. */\r
472         .pWillInfo = NULL,\r
473 \r
474         /* Send an MQTT PING request every minute to keep the connection open if\r
475         there is no other MQTT traffic. */\r
476         .keepAliveSeconds = shadowexampleKEEP_ALIVE_SECONDS,\r
477 \r
478         /* The client identifier is used to uniquely identify this MQTT client to\r
479          * the MQTT broker.  In a production device the identifier can be something\r
480          * unique, such as a device serial number. */\r
481         .pClientIdentifier = awsiotdemoprofileCLIENT_IDENTIFIER,\r
482         .clientIdentifierLength = ( uint16_t ) sizeof( awsiotdemoprofileCLIENT_IDENTIFIER ) - 1,\r
483 \r
484         /* This example does not authenticate the client and therefore username and\r
485          * password fields are not used. */\r
486         .pUserName = NULL,\r
487         .userNameLength = 0,\r
488         .pPassword = NULL,\r
489         .passwordLength = 0\r
490 };\r
491 /*-----------------------------------------------------------*/\r
492 \r
493 void vStartShadowDeviceOperationsDemo( void )\r
494 {\r
495 TickType_t xShortDelay = ( TickType_t ) pdMS_TO_TICKS( ( TickType_t ) 500 );\r
496 \r
497         /* Wait a short time to allow receipt of the ARP replies. */\r
498         vTaskDelay( xShortDelay );\r
499 \r
500         /* This example uses a single application task, which in turn is used to\r
501          * connect, subscribe, publish, unsubscribe and disconnect from the MQTT\r
502          * broker. */\r
503         xTaskCreate( prvShadowDemoTask,       /* Function that implements the task. */\r
504                                  "ShadowDemo",            /* Text name for the task - only used for debugging. */\r
505                                  democonfigDEMO_STACKSIZE,/* Size of stack (in words, not bytes) to allocate for the task. */\r
506                                  NULL,                    /* Task parameter - not used in this case. */\r
507                                  tskIDLE_PRIORITY,        /* Task priority, must be between 0 and configMAX_PRIORITIES - 1. */\r
508                                  NULL );                  /* Used to pass out a handle to the created task - not used in this case. */\r
509 }\r
510 /*-----------------------------------------------------------*/\r
511 \r
512 static void prvShadowDemoTask( void *pvParameters )\r
513 {\r
514 uint32_t ulNotificationValue = 0;\r
515 const TickType_t xNoDelay = ( TickType_t ) 0;\r
516 \r
517         /* Remove compiler warnings about unused parameters. */\r
518         ( void ) pvParameters;\r
519 \r
520         /* One time initialization of the libraries used by this demo. */\r
521         prvInitialiseLibraries();\r
522 \r
523         for( ; ; )\r
524         {\r
525                 /* Don't expect any notifications to be pending yet. */\r
526                 configASSERT( ulTaskNotifyTake( pdTRUE, xNoDelay ) == 0 );\r
527 \r
528                 /****************************** Connect. ******************************/\r
529 \r
530                 /* Establish a connection to the AWS IoT MQTT broker. This example connects to\r
531                  * the MQTT broker as specified in awsiotdemoprofileAWS_ENDPOINT and\r
532                  * awsiotdemoprofileAWS_MQTT_PORT at the top of this file.\r
533                  */\r
534                 configPRINTF( ( "Attempt to connect to %s\r\n", awsiotdemoprofileAWS_ENDPOINT ) );\r
535                 prvMQTTConnect();\r
536                 configPRINTF( ( "Connected to %s\r\n", awsiotdemoprofileAWS_ENDPOINT ) );\r
537 \r
538                 /************************ Create a semaphore **************************/\r
539 \r
540                 /* Creates a semaphore to synchronize between delta callback and\r
541                  * Shadow updates.\r
542                  */\r
543                 configPRINTF( ( "Creating delta semaphore\r\n" ) );\r
544                 configASSERT( xSemaphoreCreateCountingStatic( 1, 0, &xDeltaSemaphore.xSemaphore ) != NULL );\r
545 \r
546                 /************************ Set shadow callbacks ************************/\r
547 \r
548                 /* Sets the updated callback and delta callback */\r
549                 configPRINTF( ( "Setting the updated callback and  delta callback\r\n" ) );\r
550                 prvSetShadowCallbacks();\r
551 \r
552                 /************************ Clear shadow document ***********************/\r
553 \r
554                 /* Clears the Shadow document if it exists already */\r
555                 configPRINTF( ( "Clearing the Shadow document if it already exits\r\n" ) );\r
556                 prvClearShadowDocument();\r
557 \r
558                 /*********************** Send Shadow updates **************************/\r
559 \r
560                 /* Send Shadow updates for shadowexampleUPDATE_COUNT times.\r
561                  * For each Shadow update, it waits on xDeltaSemaphore. xDeltaSemaphore\r
562                  * will be posted by the delta callback.\r
563                  */\r
564                 configPRINTF( ( "Sending Shadow updates\r\n" ) );\r
565                 prvSendShadowUpdates();\r
566 \r
567                 /************************ Clear shadow document ***********************/\r
568 \r
569                 /* Clears the Shadow document at the end of the demo */\r
570                 configPRINTF( ( "Clearing the Shadow document\r\n" ) );\r
571                 prvClearShadowDocument();\r
572 \r
573                 /************** Clear callbacks and Disconnect MQTT. ******************/\r
574 \r
575                 /* Clear updated callback and delta callback */\r
576                 configPRINTF( ( "Clearing the Shadow updated callback and delta callback\r\n" ) );\r
577                 prvClearShadowCallbacks();\r
578 \r
579                 /* Disconnect MQTT gracefully. */\r
580                 prvMQTTDisconnect();\r
581                 configPRINTF( ( "Disconnected from %s\r\n\r\n", awsiotdemoprofileAWS_ENDPOINT ) );\r
582 \r
583                 /* Wait for the disconnect operation to complete which is informed to us\r
584                  * by the disconnect callback (prvExample_OnDisconnect)by setting\r
585                  * the shadowexampleDISCONNECTED_BIT in this task's notification value.\r
586                  * Note that the bit is cleared in the task's notification value to\r
587                  * ensure that it is ready for the next run. */\r
588                 xTaskNotifyWait( 0UL,                           /* Don't clear any bits on entry. */\r
589                                                  shadowexampleDISCONNECTED_BIT, /* Clear bit on exit. */\r
590                                                  &( ulNotificationValue ),      /* Obtain the notification value. */\r
591                                                  pdMS_TO_TICKS( shadowexampleMQTT_TIMEOUT_MS ) );\r
592                 configASSERT( ( ulNotificationValue & shadowexampleDISCONNECTED_BIT ) == shadowexampleDISCONNECTED_BIT );\r
593 \r
594                 /* Destroy the delta semaphore*/\r
595                 vSemaphoreDelete( ( SemaphoreHandle_t ) &xDeltaSemaphore.xSemaphore );\r
596 \r
597                 /* Clear the current reported shadow state to toggle the reported state. */\r
598                 lDevicePowerOnState = 0;\r
599 \r
600                 /* Wait for some time between two iterations to ensure that we do not\r
601                  * bombard the broker. */\r
602                 configPRINTF( ( "prvShadowDemoTask() completed an iteration successfully. Total free heap is %u\r\n", xPortGetFreeHeapSize() ) );\r
603                 configPRINTF( ( "Demo completed successfully.\r\n" ) );\r
604                 configPRINTF( ( "Short delay before starting the next iteration... \r\n\r\n" ) );\r
605                 vTaskDelay( pdMS_TO_TICKS( shadowexampleLOOP_WAIT_PERIOD_MS ) );\r
606         }\r
607 }\r
608 /*-----------------------------------------------------------*/\r
609 \r
610 static void prvExample_OnDisconnect( void * pvCallbackContext,\r
611                                                                          IotMqttCallbackParam_t * pxCallbackParams )\r
612 {\r
613 TaskHandle_t xDemoTaskHandle = ( TaskHandle_t ) pvCallbackContext;\r
614 \r
615         /* Ensure that we initiated the disconnect. */\r
616         configASSERT( pxCallbackParams->u.disconnectReason == IOT_MQTT_DISCONNECT_CALLED );\r
617 \r
618         /* Inform the demo task about the disconnect. */\r
619         xTaskNotify( xDemoTaskHandle,\r
620                                  shadowexampleDISCONNECTED_BIT,\r
621                                  eSetBits /* Set the shadowexampleDISCONNECTED_BIT in the demo task's notification value. */\r
622                                  );\r
623 }\r
624 /*-----------------------------------------------------------*/\r
625 \r
626 static void prvMQTTConnect( void )\r
627 {\r
628 IotMqttError_t xResult;\r
629 \r
630         /* Set the context to pass into the disconnect callback function. */\r
631         xNetworkInfo.disconnectCallback.pCallbackContext = ( void * ) xTaskGetCurrentTaskHandle();\r
632 \r
633         /* Establish the connection to the MQTT broker - It is a blocking call and\r
634          * will return only when connection is complete or a timeout occurs. */\r
635         xResult = IotMqtt_Connect( &( xNetworkInfo ),\r
636                                                            &( xConnectInfo ),\r
637                                                            shadowexampleMQTT_TIMEOUT_MS,\r
638                                                            &( xMQTTConnection ) );\r
639         configASSERT( xResult == IOT_MQTT_SUCCESS );\r
640 }\r
641 /*-----------------------------------------------------------*/\r
642 \r
643 static void prvMQTTDisconnect( void )\r
644 {\r
645         /* Send a MQTT DISCONNECT packet to the MQTT broker to do a graceful\r
646          * disconnect. */\r
647         IotMqtt_Disconnect( xMQTTConnection,\r
648                                                 0 /* flags - 0 means a graceful disconnect by sending MQTT DISCONNECT. */\r
649                                                 );\r
650 }\r
651 /*-----------------------------------------------------------*/\r
652 \r
653 static void prvSetShadowCallbacks( void )\r
654 {\r
655 AwsIotShadowError_t xCallbackStatus = AWS_IOT_SHADOW_STATUS_PENDING;\r
656 AwsIotShadowCallbackInfo_t xDeltaCallback = AWS_IOT_SHADOW_CALLBACK_INFO_INITIALIZER,\r
657                                                    xUpdatedCallback = AWS_IOT_SHADOW_CALLBACK_INFO_INITIALIZER;\r
658 \r
659         /* Set the functions for callbacks. */\r
660         xDeltaCallback.pCallbackContext = &xDeltaSemaphore;\r
661         xDeltaCallback.function = prvShadowDeltaCallback;\r
662         xUpdatedCallback.function = prvShadowUpdatedCallback;\r
663 \r
664         /************************ Set delta callbacks ****************************/\r
665 \r
666         /* Set the delta callback, which notifies of different desired and reported\r
667          * Shadow states. */\r
668         xCallbackStatus = AwsIotShadow_SetDeltaCallback( xMQTTConnection,\r
669                                                                                                          awsiotdemoprofileCLIENT_IDENTIFIER,\r
670                                                                                                          shadowexampleCLIENT_IDENTIFIER_LENGTH,\r
671                                                                                                          0, &xDeltaCallback );\r
672         configASSERT( xCallbackStatus == AWS_IOT_SHADOW_SUCCESS );\r
673 \r
674         /************************ Set updated callbacks **************************/\r
675 \r
676         /* Set the updated callback, which notifies when a Shadow document is\r
677         * changed. */\r
678         xCallbackStatus = AwsIotShadow_SetUpdatedCallback( xMQTTConnection,\r
679                                                                                                            awsiotdemoprofileCLIENT_IDENTIFIER,\r
680                                                                                                            shadowexampleCLIENT_IDENTIFIER_LENGTH,\r
681                                                                                                            0, &xUpdatedCallback );\r
682 \r
683         configASSERT( xCallbackStatus == AWS_IOT_SHADOW_SUCCESS );\r
684 }\r
685 /*-----------------------------------------------------------*/\r
686 \r
687 static void prvClearShadowCallbacks( void )\r
688 {\r
689 AwsIotShadowError_t xCallbackStatus = AWS_IOT_SHADOW_STATUS_PENDING;\r
690 \r
691         /************************ Clear delta callbacks **************************/\r
692         xCallbackStatus = AwsIotShadow_SetDeltaCallback( xMQTTConnection,\r
693                                                                                                          awsiotdemoprofileCLIENT_IDENTIFIER,\r
694                                                                                                          shadowexampleCLIENT_IDENTIFIER_LENGTH,\r
695                                                                                                          0, NULL );\r
696         configASSERT( xCallbackStatus == AWS_IOT_SHADOW_SUCCESS );\r
697 \r
698         /************************ Clear updated callbacks ************************/\r
699         xCallbackStatus = AwsIotShadow_SetUpdatedCallback( xMQTTConnection,\r
700                                                                                                            awsiotdemoprofileCLIENT_IDENTIFIER,\r
701                                                                                                            shadowexampleCLIENT_IDENTIFIER_LENGTH,\r
702                                                                                                            0, NULL );\r
703         configASSERT( xCallbackStatus == AWS_IOT_SHADOW_SUCCESS );\r
704 }\r
705 /*-----------------------------------------------------------*/\r
706 \r
707 static void prvShadowDeltaCallback( void * pCallbackContext,\r
708                                                                         AwsIotShadowCallbackParam_t * pxCallbackParam )\r
709 {\r
710 BaseType_t xDeltaFound = pdFALSE;\r
711 const char * pcDelta = NULL;\r
712 size_t xDeltaLength = 0;\r
713 IotSemaphore_t * pxDeltaSemaphore = pCallbackContext;\r
714 uint32_t ulUpdateDocumentLength = 0;\r
715 AwsIotShadowError_t xShadowStatus = AWS_IOT_SHADOW_STATUS_PENDING;\r
716 AwsIotShadowDocumentInfo_t xUpdateDocument = AWS_IOT_SHADOW_DOCUMENT_INFO_INITIALIZER;\r
717 uint8_t ucNewState = 0;\r
718 \r
719         configASSERT( pxDeltaSemaphore != NULL );\r
720         configASSERT( pxCallbackParam != NULL );\r
721 \r
722         /* A buffer containing the update document. It has static duration to prevent\r
723          * it from being placed on the call stack.This is only safe because there\r
724          * is only one task in the task pool so this function cannot be called from\r
725          * two tasks simultaneously. */\r
726         static char cUpdateDocument[ shadowexampleREPORTED_JSON_SIZE + 1 ] = { 0 };\r
727 \r
728         /****************** Get delta state from Shadow document *****************/\r
729         /* Check if there is a different "powerOn" state in the Shadow. */\r
730         xDeltaFound = prvGetDelta( pxCallbackParam->u.callback.pDocument,\r
731                                                            pxCallbackParam->u.callback.documentLength,\r
732                                                            "powerOn",\r
733                                                            &pcDelta,\r
734                                                            &xDeltaLength );\r
735 \r
736         configASSERT( xDeltaFound == pdTRUE );\r
737 \r
738         /* Change the current state based on the value in the delta document. */\r
739         if( *pcDelta == '0' )\r
740         {\r
741                 ucNewState = 0;\r
742         }\r
743         else if( *pcDelta == '1' )\r
744         {\r
745                 ucNewState = 1;\r
746         }\r
747         else\r
748         {\r
749                 configPRINTF( ( "Unknown powerOn state parsed from delta document.\r\n" ) );\r
750 \r
751                 /* Set new state to current state to ignore the delta document. */\r
752                 ucNewState = lDevicePowerOnState;\r
753         }\r
754 \r
755         if( ucNewState != lDevicePowerOnState )\r
756         {\r
757                 /* Toggle state. */\r
758                 configPRINTF( ( "%.*s changing state from %d to %d.\r\n",\r
759                                                 pxCallbackParam->thingNameLength,\r
760                                                 pxCallbackParam->pThingName,\r
761                                                 lDevicePowerOnState,\r
762                                                 ucNewState ) );\r
763 \r
764                 lDevicePowerOnState = ucNewState;\r
765 \r
766                 /* Set the common members to report the new state. */\r
767                 xUpdateDocument.pThingName = pxCallbackParam->pThingName;\r
768                 xUpdateDocument.thingNameLength = pxCallbackParam->thingNameLength;\r
769                 xUpdateDocument.u.update.pUpdateDocument = cUpdateDocument;\r
770                 xUpdateDocument.u.update.updateDocumentLength = shadowexampleREPORTED_JSON_SIZE;\r
771 \r
772                 /* Generate a Shadow document for the reported state. To keep the client\r
773                  * token within 6 characters, it is modded by 1000000. */\r
774                 ulUpdateDocumentLength = snprintf( cUpdateDocument,\r
775                                                                                    shadowexampleREPORTED_JSON_SIZE + 1,\r
776                                                                                    shadowexampleREPORTED_JSON,\r
777                                                                                    ( int ) lDevicePowerOnState,\r
778                                                                                    ( long unsigned ) ( IotClock_GetTimeMs() % 1000000 ) );\r
779 \r
780                 /* Check if the reported state document is generated for Shadow update*/\r
781                 configASSERT( ( size_t ) ulUpdateDocumentLength == shadowexampleREPORTED_JSON_SIZE );\r
782 \r
783                 /* Send the Shadow update. Its result is not checked by waiting for the\r
784                  * callback, as the Shadow updated callback will report if the Shadow\r
785                  * was successfully updated. As the Shadow is constantly updated\r
786                  * in this demo, the "Keep Subscriptions" flag is passed to this\r
787                  * function. */\r
788                 xShadowStatus = AwsIotShadow_UpdateAsync( pxCallbackParam->mqttConnection,\r
789                                                                                                   &xUpdateDocument,\r
790                                                                                                   AWS_IOT_SHADOW_FLAG_KEEP_SUBSCRIPTIONS,\r
791                                                                                                   NULL,\r
792                                                                                                   NULL );\r
793 \r
794                 configASSERT( xShadowStatus == AWS_IOT_SHADOW_STATUS_PENDING );\r
795                 configPRINTF( ( "%.*s sent new state report: %.*s\r\n",\r
796                                                 pxCallbackParam->thingNameLength,\r
797                                                 pxCallbackParam->pThingName,\r
798                                                 shadowexampleREPORTED_JSON_SIZE,\r
799                                                 cUpdateDocument ) );\r
800 \r
801                 /* Post to the delta semaphore to unblock the thread sending Shadow updates. */\r
802                 xSemaphoreGive( ( SemaphoreHandle_t ) &pxDeltaSemaphore->xSemaphore );\r
803         }\r
804 }\r
805 /*-----------------------------------------------------------*/\r
806 \r
807 static void prvShadowUpdatedCallback( void * pCallbackContext,\r
808                                                                           AwsIotShadowCallbackParam_t * pxCallbackParam )\r
809 {\r
810 BaseType_t xPreviousFound = pdFALSE, xCurrentFound = pdFALSE;\r
811 const char * pcPrevious = NULL, * pcCurrent = NULL;\r
812 size_t xPreviousLength = 0, xCurrentLength = 0;\r
813 \r
814         /* Silence warnings about unused parameters. */\r
815         ( void ) pCallbackContext;\r
816 \r
817         configASSERT( pxCallbackParam != NULL );\r
818 \r
819         /****************** Get previous state from Shadow document **************/\r
820         /* Find the previous Shadow document. */\r
821         xPreviousFound = prvGetUpdatedState( pxCallbackParam->u.callback.pDocument,\r
822                                                                                  pxCallbackParam->u.callback.documentLength,\r
823                                                                                  "previous",\r
824                                                                                  &pcPrevious,\r
825                                                                                  &xPreviousLength );\r
826 \r
827         /****************** Get current state from Shadow document **************/\r
828         /* Find the current Shadow document. */\r
829         xCurrentFound = prvGetUpdatedState( pxCallbackParam->u.callback.pDocument,\r
830                                                                                 pxCallbackParam->u.callback.documentLength,\r
831                                                                                 "current",\r
832                                                                                 &pcCurrent,\r
833                                                                                 &xCurrentLength );\r
834 \r
835         configASSERT( ( xPreviousFound == pdTRUE ) || ( xCurrentFound == pdTRUE ) );\r
836 \r
837         /* Log the previous and current states. */\r
838         configPRINTF( ( "Shadow was updated!\r\n"\r
839                                         "Previous: {\"state\":%.*s}\r\n"\r
840                                         "Current:  {\"state\":%.*s}\r\n",\r
841                                         xPreviousLength,\r
842                                         pcPrevious,\r
843                                         xCurrentLength,\r
844                                         pcCurrent ) );\r
845 }\r
846 /*-----------------------------------------------------------*/\r
847 \r
848 static BaseType_t prvGetDelta( const char * pcDeltaDocument,\r
849                                                            size_t xDeltaDocumentLength,\r
850                                                            const char * pcDeltaKey,\r
851                                                            const char ** pcDelta,\r
852                                                            size_t * pcDeltaLength )\r
853 {\r
854 BaseType_t xStateFound = pdFALSE, xDeltaFound = pdFALSE;\r
855 const size_t xDeltaKeyLength = strlen( pcDeltaKey );\r
856 const char * pcState = NULL;\r
857 size_t xStateLength = 0;\r
858 \r
859         configASSERT( pcDeltaDocument != NULL );\r
860         configASSERT( pcDeltaKey != NULL );\r
861         /****************** Get state from Shadow document ***********************/\r
862 \r
863         /* Note: This parser used is specific for parsing AWS IoT document received\r
864          * through a mutually authenticated connection. This parser will not check\r
865          * for the correctness of the document as it is designed for low memory\r
866          * footprint rather than checking for correctness of the document. This\r
867          * parser is not meant to be used as a general purpose JSON parser.\r
868          */\r
869         xStateFound = ( BaseType_t ) AwsIotDocParser_FindValue(\r
870                 pcDeltaDocument,\r
871                 xDeltaDocumentLength,\r
872                 "state",\r
873                 5,\r
874                 &pcState,\r
875                 &xStateLength );\r
876 \r
877         configASSERT( xStateFound == pdTRUE );\r
878 \r
879         /********** Get delta key from state section of Shadow document **********/\r
880 \r
881         /* Note: This parser used is specific for parsing AWS IoT document received\r
882          * through a mutually authenticated connection. This parser will not check\r
883          * for the correctness of the document as it is designed for low memory\r
884          * footprint rather than checking for correctness of the document. This\r
885          * parser is not meant to be used as a general purpose JSON parser.\r
886          */\r
887         xDeltaFound = ( BaseType_t ) AwsIotDocParser_FindValue(\r
888                 pcState,\r
889                 xStateLength,\r
890                 pcDeltaKey,\r
891                 xDeltaKeyLength,\r
892                 pcDelta,\r
893                 pcDeltaLength );\r
894 \r
895         return xDeltaFound;\r
896 }\r
897 /*-----------------------------------------------------------*/\r
898 \r
899 static BaseType_t prvGetUpdatedState( const char * pcUpdatedDocument,\r
900                                                                           size_t xUpdatedDocumentLength,\r
901                                                                           const char * pcSectionKey,\r
902                                                                           const char ** ppcState,\r
903                                                                           size_t * ppcStateLength )\r
904 {\r
905 BaseType_t xSectionFound = pdFALSE, xStateFound = pdFALSE;\r
906 const size_t xSectionKeyLength = strlen( pcSectionKey );\r
907 const char * pcSection = NULL;\r
908 size_t xSectionLength = 0;\r
909 \r
910         configASSERT( pcUpdatedDocument != NULL );\r
911         configASSERT( pcSectionKey != NULL );\r
912 \r
913         /*********** Find the given section in the updated document. *************/\r
914 \r
915         /* Note: This parser used is specific for parsing AWS IoT document received\r
916          * through a mutually authenticated connection. This parser will not check\r
917          * for the correctness of the document as it is designed for low memory\r
918          * footprint rather than checking for correctness of the document. This\r
919          * parser is not meant to be used as a general purpose JSON parser.\r
920          */\r
921         xSectionFound = ( BaseType_t ) AwsIotDocParser_FindValue(\r
922                 pcUpdatedDocument,\r
923                 xUpdatedDocumentLength,\r
924                 pcSectionKey,\r
925                 xSectionKeyLength,\r
926                 &pcSection,\r
927                 &xSectionLength );\r
928 \r
929         configASSERT( xSectionFound == pdTRUE );\r
930 \r
931         /*********** Find the state key within the section found *****************/\r
932 \r
933         /* Find the "state" key within the "previous" or "current" section.\r
934          *\r
935          * Note: This parser used is specific for parsing AWS IoT document received\r
936          * through a mutually authenticated connection. This parser will not check\r
937          * for the correctness of the document as it is designed for low memory\r
938          * footprint rather than checking for correctness of the document. This\r
939          * parser is not meant to be used as a general purpose JSON parser.\r
940          */\r
941         xStateFound = ( BaseType_t ) AwsIotDocParser_FindValue(\r
942                 pcSection,\r
943                 xSectionLength,\r
944                 "state",\r
945                 5,\r
946                 ppcState,\r
947                 ppcStateLength );\r
948 \r
949         return xStateFound;\r
950 }\r
951 /*-----------------------------------------------------------*/\r
952 \r
953 static void prvClearShadowDocument( void )\r
954 {\r
955 AwsIotShadowError_t xDeleteStatus = AWS_IOT_SHADOW_STATUS_PENDING;\r
956 \r
957         /************************* Delete Shadow document ************************/\r
958         xDeleteStatus = AwsIotShadow_DeleteSync( xMQTTConnection,\r
959                                                                                          awsiotdemoprofileCLIENT_IDENTIFIER,\r
960                                                                                          shadowexampleCLIENT_IDENTIFIER_LENGTH,\r
961                                                                                          0, shadowexampleMQTT_TIMEOUT_MS );\r
962         configASSERT( ( xDeleteStatus == AWS_IOT_SHADOW_SUCCESS ) || ( xDeleteStatus == AWS_IOT_SHADOW_NOT_FOUND ) );\r
963 \r
964         configPRINTF( ( "Successfully cleared Shadow of %.*s.\r\n",\r
965                                         shadowexampleCLIENT_IDENTIFIER_LENGTH,\r
966                                         awsiotdemoprofileCLIENT_IDENTIFIER ) );\r
967 }\r
968 /*-----------------------------------------------------------*/\r
969 \r
970 static void prvSendShadowUpdates( void )\r
971 {\r
972 int32_t lIndex = 0, lDesiredState = 0, lStatus = 0;\r
973 AwsIotShadowError_t xShadowStatus = AWS_IOT_SHADOW_STATUS_PENDING;\r
974 AwsIotShadowDocumentInfo_t xUpdateDocument = AWS_IOT_SHADOW_DOCUMENT_INFO_INITIALIZER;\r
975 \r
976         /* A buffer containing the update document. It has static duration to prevent\r
977          * it from being placed on the call stack. */\r
978         static char cUpdateDocument[ shadowexampleDESIRED_JSON_SIZE + 1 ] = { 0 };\r
979 \r
980         /********** Set the common members of Shadow update document *************/\r
981         xUpdateDocument.pThingName = awsiotdemoprofileCLIENT_IDENTIFIER;\r
982         xUpdateDocument.thingNameLength = shadowexampleCLIENT_IDENTIFIER_LENGTH;\r
983         xUpdateDocument.u.update.pUpdateDocument = cUpdateDocument;\r
984         xUpdateDocument.u.update.updateDocumentLength = shadowexampleDESIRED_JSON_SIZE;\r
985 \r
986         /*************** Publish Shadow updates at a set period. *****************/\r
987         for( lIndex = 1; lIndex <= shadowexampleUPDATE_COUNT; lIndex++ )\r
988         {\r
989                 /* Toggle the desired state. */\r
990                 lDesiredState = !( lDesiredState );\r
991 \r
992                 /* Generate a Shadow desired state document, using a timestamp for the client\r
993                  * token. To keep the client token within 6 characters, it is modded by 1000000. */\r
994                 lStatus = snprintf( cUpdateDocument,\r
995                                                         shadowexampleDESIRED_JSON_SIZE + 1,\r
996                                                         shadowexampleDESIRED_JSON,\r
997                                                         ( int ) lDesiredState,\r
998                                                         ( long unsigned ) ( IotClock_GetTimeMs() % 1000000 ) );\r
999 \r
1000                 /* Check for errors from snprintf. The expected value is the length of\r
1001                  * the desired JSON document less the format specifier for the state. */\r
1002                 configASSERT( lStatus == shadowexampleDESIRED_JSON_SIZE );\r
1003 \r
1004                 configPRINTF( ( "Sending Shadow update %d of %d: %s\r\n",\r
1005                                                 lIndex,\r
1006                                                 shadowexampleUPDATE_COUNT,\r
1007                                                 cUpdateDocument ) );\r
1008 \r
1009                 /* Send the Shadow update. Because the Shadow is constantly updated in\r
1010                  * this demo, the "Keep Subscriptions" flag is passed to this function.\r
1011                  * Note that this flag only needs to be passed on the first call, but\r
1012                  * passing it for subsequent calls is fine.\r
1013                  */\r
1014                 xShadowStatus = AwsIotShadow_UpdateSync( xMQTTConnection,\r
1015                                                                                                  &xUpdateDocument,\r
1016                                                                                                  AWS_IOT_SHADOW_FLAG_KEEP_SUBSCRIPTIONS,\r
1017                                                                                                  shadowexampleMQTT_TIMEOUT_MS );\r
1018 \r
1019                 configASSERT( xShadowStatus == AWS_IOT_SHADOW_SUCCESS );\r
1020 \r
1021                 configPRINTF( ( "Successfully sent Shadow update %d of %d.\r\n",\r
1022                                                 lIndex,\r
1023                                                 shadowexampleUPDATE_COUNT ) );\r
1024 \r
1025                 /* Wait for the delta callback to change its state before continuing. */\r
1026                 configASSERT( xSemaphoreTake( ( SemaphoreHandle_t ) &xDeltaSemaphore.xSemaphore,\r
1027                                                                           pdMS_TO_TICKS( shadowexampleWAIT_PERIOD_FOR_DELTA_MS ) ) == pdTRUE );\r
1028 \r
1029                 IotClock_SleepMs( shadowexampleUPDATE_PERIOD_MS );\r
1030         }\r
1031 \r
1032         /* Remove persistent subscriptions. In the AwsIotShadow_UpdateSync call, we have used the */\r
1033         xShadowStatus = AwsIotShadow_RemovePersistentSubscriptions( xMQTTConnection,\r
1034                                                                                                                                 awsiotdemoprofileCLIENT_IDENTIFIER,\r
1035                                                                                                                                 shadowexampleCLIENT_IDENTIFIER_LENGTH,\r
1036                                                                                                                                 AWS_IOT_SHADOW_FLAG_REMOVE_UPDATE_SUBSCRIPTIONS );\r
1037 \r
1038         configASSERT( xShadowStatus == AWS_IOT_SHADOW_SUCCESS );\r
1039 }\r
1040 /*-----------------------------------------------------------*/\r
1041 \r
1042 static void prvInitialiseLibraries( void )\r
1043 {\r
1044 IotTaskPoolError_t xTaskPoolResult;\r
1045 IotMqttError_t xResult;\r
1046 IotNetworkError_t xNetworkResult;\r
1047 \r
1048         /* The MQTT library needs a task pool, so create the system task pool. */\r
1049         xTaskPoolResult = IotTaskPool_CreateSystemTaskPool( &( xTaskPoolParameters ) );\r
1050         configASSERT( xTaskPoolResult == IOT_TASKPOOL_SUCCESS );\r
1051 \r
1052         /* Initialize the network stack abstraction for FreeRTOS. */\r
1053         xNetworkResult = IotNetworkFreeRTOS_Init();\r
1054         configASSERT( xNetworkResult == IOT_NETWORK_SUCCESS );\r
1055 \r
1056         /* MQTT library must be initialized before it can be used. This is just one\r
1057          * time initialization. */\r
1058         xResult = IotMqtt_Init();\r
1059         configASSERT( xResult == IOT_MQTT_SUCCESS );\r
1060 \r
1061         /* Initialize Shadow library*/\r
1062         xResult = AwsIotShadow_Init( shadowexampleUSE_DEFAULT_MQTT_TIMEOUT );\r
1063         configASSERT( xResult == AWS_IOT_SHADOW_SUCCESS );\r
1064 }\r
1065 /*-----------------------------------------------------------*/\r