xref: /CoreMQTT-Agent-v1.2.0/source/include/core_mqtt_agent.h (revision 86c51db1a7d060744a06fa3619bd3ba86a938a94)
1 /*
2  * coreMQTT Agent v1.2.0
3  * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of
6  * this software and associated documentation files (the "Software"), to deal in
7  * the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9  * the Software, and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 /**
24  * @file core_mqtt_agent.h
25  * @brief Functions for running a coreMQTT client in a dedicated thread.
26  */
27 #ifndef CORE_MQTT_AGENT_H
28 #define CORE_MQTT_AGENT_H
29 
30 /* *INDENT-OFF* */
31 #ifdef __cplusplus
32     extern "C" {
33 #endif
34 /* *INDENT-ON* */
35 
36 /* MQTT library includes. */
37 #include "core_mqtt.h"
38 #include "core_mqtt_state.h"
39 
40 #include "core_mqtt_agent_config_defaults.h"
41 
42 /* Command messaging interface include. */
43 #include "core_mqtt_agent_message_interface.h"
44 
45 /**
46  * @ingroup mqtt_agent_enum_types
47  * @brief A type of command for interacting with the MQTT API.
48  */
49 typedef enum MQTTCommandType
50 {
51     NONE = 0,    /**< @brief No command received.  Must be zero (its memset() value). */
52     PROCESSLOOP, /**< @brief Call MQTT_ProcessLoop(). */
53     PUBLISH,     /**< @brief Call MQTT_Publish(). */
54     SUBSCRIBE,   /**< @brief Call MQTT_Subscribe(). */
55     UNSUBSCRIBE, /**< @brief Call MQTT_Unsubscribe(). */
56     PING,        /**< @brief Call MQTT_Ping(). */
57     CONNECT,     /**< @brief Call MQTT_Connect(). */
58     DISCONNECT,  /**< @brief Call MQTT_Disconnect(). */
59     TERMINATE,   /**< @brief Exit the command loop and stop processing commands. */
60     NUM_COMMANDS /**< @brief The number of command types handled by the agent. */
61 } MQTTAgentCommandType_t;
62 
63 struct MQTTAgentContext;
64 struct MQTTAgentCommandContext;
65 
66 /**
67  * @ingroup mqtt_agent_struct_types
68  * @brief Struct holding return codes and outputs from a command
69  */
70 typedef struct MQTTAgentReturnInfo
71 {
72     MQTTStatus_t returnCode; /**< Return code of the MQTT command. */
73     uint8_t * pSubackCodes;  /**< Array of SUBACK statuses, for a SUBSCRIBE command. */
74 } MQTTAgentReturnInfo_t;
75 
76 /**
77  * @ingroup mqtt_agent_struct_types
78  * @brief Struct containing context for a specific command.
79  *
80  * @note An instance of this struct and any variables it points to MUST stay
81  * in scope until the associated command is processed, and its callback called.
82  */
83 typedef struct MQTTAgentCommandContext MQTTAgentCommandContext_t;
84 
85 /**
86  * @ingroup mqtt_agent_callback_types
87  * @brief Callback function called when a command completes.
88  *
89  * @param[in] pCmdCallbackContext The callback context passed to the original command.
90  * @param[in] pReturnInfo A struct of status codes and outputs from the command.
91  *
92  * @note A command should not be considered complete until this callback is
93  * called, and the arguments that the command uses MUST stay in scope until such happens.
94  *
95  * @note The callback MUST NOT block as it runs in the context of the MQTT agent
96  * task. If the callback calls any MQTT Agent API to enqueue a command, the
97  * blocking time (blockTimeMs member of MQTTAgentCommandInfo_t) MUST be zero. If the
98  * application wants to enqueue command(s) with non-zero blocking time, the
99  * callback can notify a different task to enqueue command(s) to the MQTT agent.
100  */
101 typedef void (* MQTTAgentCommandCallback_t )( MQTTAgentCommandContext_t * pCmdCallbackContext,
102                                               MQTTAgentReturnInfo_t * pReturnInfo );
103 
104 /**
105  * @ingroup mqtt_agent_struct_types
106  * @brief The commands sent from the APIs to the MQTT agent task.
107  *
108  * @note The structure used to pass information from the public facing API into the
109  * agent task. */
110 struct MQTTAgentCommand
111 {
112     MQTTAgentCommandType_t commandType;                  /**< @brief Type of command. */
113     void * pArgs;                                        /**< @brief Arguments of command. */
114     MQTTAgentCommandCallback_t pCommandCompleteCallback; /**< @brief Callback to invoke upon completion. */
115     MQTTAgentCommandContext_t * pCmdContext;             /**< @brief Context for completion callback. */
116 };
117 
118 /**
119  * @ingroup mqtt_agent_struct_types
120  * @brief Information for a pending MQTT ack packet expected by the agent.
121  */
122 typedef struct MQTTAckInfo
123 {
124     uint16_t packetId;                     /**< Packet ID of the pending acknowledgment. */
125     MQTTAgentCommand_t * pOriginalCommand; /**< Command expecting acknowledgment. */
126 } MQTTAgentAckInfo_t;
127 
128 /**
129  * @ingroup mqtt_agent_callback_types
130  * @brief Callback function called when receiving a publish.
131  *
132  * @param[in] pMqttAgentContext The context of the MQTT agent.
133  * @param[in] packetId The packet ID of the received publish.
134  * @param[in] pPublishInfo Deserialized publish information.
135  *
136  * @note The callback MUST NOT block as it runs in the context of the MQTT agent
137  * task. If the callback calls any MQTT Agent API to enqueue a command, the
138  * blocking time (blockTimeMs member of MQTTAgentCommandInfo_t) MUST be zero. If the
139  * application wants to enqueue command(s) with non-zero blocking time, the
140  * callback can notify a different task to enqueue command(s) to the MQTT agent.
141  */
142 typedef void (* MQTTAgentIncomingPublishCallback_t )( struct MQTTAgentContext * pMqttAgentContext,
143                                                       uint16_t packetId,
144                                                       MQTTPublishInfo_t * pPublishInfo );
145 
146 /**
147  * @ingroup mqtt_agent_struct_types
148  * @brief Information used by each MQTT agent. A context will be initialized by
149  * MQTTAgent_Init(), and every API function will accept a pointer to the
150  * initalized struct.
151  */
152 typedef struct MQTTAgentContext
153 {
154     MQTTContext_t mqttContext;                                          /**< MQTT connection information used by coreMQTT. */
155     MQTTAgentMessageInterface_t agentInterface;                         /**< Struct of function pointers for agent messaging. */
156     MQTTAgentAckInfo_t pPendingAcks[ MQTT_AGENT_MAX_OUTSTANDING_ACKS ]; /**< List of pending acknowledgment packets. */
157     MQTTAgentIncomingPublishCallback_t pIncomingCallback;               /**< Callback to invoke for incoming publishes. */
158     void * pIncomingCallbackContext;                                    /**< Context for incoming publish callback. */
159     bool packetReceivedInLoop;                                          /**< Whether a MQTT_ProcessLoop() call received a packet. */
160 } MQTTAgentContext_t;
161 
162 /**
163  * @ingroup mqtt_agent_struct_types
164  * @brief Struct holding arguments for a SUBSCRIBE or UNSUBSCRIBE call.
165  */
166 typedef struct MQTTAgentSubscribeArgs
167 {
168     MQTTSubscribeInfo_t * pSubscribeInfo; /**< @brief List of MQTT subscriptions. */
169     size_t numSubscriptions;              /**< @brief Number of elements in `pSubscribeInfo`. */
170 } MQTTAgentSubscribeArgs_t;
171 
172 /**
173  * @ingroup mqtt_agent_struct_types
174  * @brief Struct holding arguments for a CONNECT call.
175  */
176 typedef struct MQTTAgentConnectArgs
177 {
178     MQTTConnectInfo_t * pConnectInfo; /**< @brief MQTT CONNECT packet information. */
179     MQTTPublishInfo_t * pWillInfo;    /**< @brief Optional Last Will and Testament. */
180     uint32_t timeoutMs;               /**< @brief Maximum timeout for a CONNACK packet. */
181     bool sessionPresent;              /**< @brief Output flag set if a previous session was present. */
182 } MQTTAgentConnectArgs_t;
183 
184 /**
185  * @ingroup mqtt_agent_struct_types
186  * @brief Struct holding arguments that are common to every command.
187  */
188 typedef struct MQTTAgentCommandInfo
189 {
190     MQTTAgentCommandCallback_t cmdCompleteCallback;          /**< @brief Callback to invoke upon completion. */
191     MQTTAgentCommandContext_t * pCmdCompleteCallbackContext; /**< @brief Context for completion callback. */
192     uint32_t blockTimeMs;                                    /**< @brief Maximum block time for enqueueing the command. */
193 } MQTTAgentCommandInfo_t;
194 
195 /*-----------------------------------------------------------*/
196 
197 /**
198  * @brief Perform any initialization the MQTT agent requires before it can
199  * be used. Must be called before any other function.
200  *
201  * @param[in] pMqttAgentContext Pointer to struct to initialize.
202  * @param[in] pMsgInterface Command interface to use for allocating and sending commands.
203  * @param[in] pNetworkBuffer Pointer to network buffer to use.
204  * @param[in] pTransportInterface Transport interface to use with the MQTT
205  * library.  See https://www.freertos.org/network-interface.html
206  * @param[in] getCurrentTimeMs Pointer to a function that returns a count value
207  * that increments every millisecond.
208  * @param[in] incomingCallback The callback to execute when receiving publishes.
209  * @param[in] pIncomingPacketContext A pointer to a context structure defined by
210  * the application writer.
211  *
212  * @note The @p pIncomingPacketContext context provided for the incoming publish
213  * callback MUST remain in scope throughout the period that the agent task is running.
214  *
215  * @return Appropriate status code from MQTT_Init().
216  *
217  * <b>Example</b>
218  * @code{c}
219  *
220  * // Function for obtaining a timestamp.
221  * uint32_t getTimeStampMs();
222  * // Callback function for receiving packets.
223  * void incomingPublishCallback( MQTTAgentContext_t * pMqttAgentContext,
224  *                               uint16_t packetId,
225  *                               MQTTPublishInfo_t * pPublishInfo );
226  * // Platform function for network send interface.
227  * int32_t networkSend( NetworkContext_t * pContext, const void * pBuffer, size_t bytes );
228  * // Platform for network receive interface.
229  * int32_t networkRecv( NetworkContext_t * pContext, void * pBuffer, size_t bytes );
230  *
231  * // Platform function for Agent Message Send.
232  * bool agentSendMessage( MQTTAgentMessageContext_t * pMsgCtx,
233  *                        MQTTAgentCommand_t * const * pCommandToSend,
234  *                        uint32_t blockTimeMs );
235  * // Platform function for Agent Message Receive.
236  * bool agentReceiveMessage( MQTTAgentMessageContext_t * pMsgCtx,
237  *                           MQTTAgentCommand_t ** pCommandToSend,
238  *                           uint32_t blockTimeMs );
239  * // Platform function to Get Agent Command.
240  * MQTTAgentCommand_t * getCommand( uint32_t blockTimeMs );
241  * // Platform function to Release Agent Command.
242  * bool releaseCommand( MQTTAgentCommand_t * pCommandToRelease );
243  *
244  * // Variables used in this example.
245  * MQTTAgentMessageInterface_t messageInterface;
246  * MQTTAgentMessageContext_t messageContext;
247  * MQTTAgentContext_t agentContext;
248  * TransportInterface_t transport;
249  * // Buffer for storing outgoing and incoming MQTT packets.
250  * MQTTFixedBuffer_t fixedBuffer;
251  * uint8_t buffer[ 1024 ];
252  * MQTTStatus_t status;
253  *
254  * // Set transport interface members.
255  * transport.pNetworkContext = &someTransportContext;
256  * transport.send = networkSend;
257  * transport.recv = networkRecv;
258  *
259  * // Set agent message interface members.
260  * messageInterface.pMsgCtx = &messageContext;
261  * messageInterface.send = agentSendMessage;
262  * messageInterface.recv = agentReceiveMessage;
263  * messageInterface.getCommand = getCommand;
264  * messageInterface.releaseCommand = releaseCommand;
265  *
266  * // Set buffer members.
267  * fixedBuffer.pBuffer = buffer;
268  * fixedBuffer.size = 1024;
269  *
270  * status = MQTTAgent_Init( &agentContext,
271  *                          &messageInterface,
272  *                          &networkBuffer,
273  *                          &transportInterface,
274  *                          stubGetTime,
275  *                          stubPublishCallback,
276  *                          incomingPacketContext );
277  *
278  * if( status == MQTTSuccess )
279  * {
280  *    // Do something with agentContext. The transport and message interfaces, and
281  *    // fixedBuffer structs were copied into the context, so the original structs
282  *    // do not need to stay in scope.
283  * }
284  * @endcode
285  */
286 /* @[declare_mqtt_agent_init] */
287 MQTTStatus_t MQTTAgent_Init( MQTTAgentContext_t * pMqttAgentContext,
288                              const MQTTAgentMessageInterface_t * pMsgInterface,
289                              const MQTTFixedBuffer_t * pNetworkBuffer,
290                              const TransportInterface_t * pTransportInterface,
291                              MQTTGetCurrentTimeFunc_t getCurrentTimeMs,
292                              MQTTAgentIncomingPublishCallback_t incomingCallback,
293                              void * pIncomingPacketContext );
294 /* @[declare_mqtt_agent_init] */
295 
296 /**
297  * @brief Process commands from the command queue in a loop.
298  *
299  * @param[in] pMqttAgentContext The MQTT agent to use.
300  *
301  * @return appropriate error code, or #MQTTSuccess from a successful disconnect
302  * or termination.
303  *
304  * <b>Example</b>
305  * @code{c}
306  *
307  * // Variables used in this example.
308  * MQTTStatus_t status;
309  * MQTTAgentContext_t mqttAgentContext;
310  *
311  * status = MQTTAgent_CommandLoop( &mqttAgentContext );
312  *
313  * // The function returns on either receiving a terminate command,
314  * // undergoing network disconnection OR encountering an error.
315  * if( ( status == MQTTSuccess ) && ( mqttAgentContext.mqttContext.connectStatus == MQTTNotConnected ) )
316  * {
317  *    // A terminate command was processed and MQTT connection was closed.
318  *    // Need to close socket connection.
319  *    Platform_DisconnectNetwork( mqttAgentContext.mqttContext.transportInterface.pNetworkContext );
320  * }
321  * else if( status == MQTTSuccess )
322  * {
323  *    // Terminate command was processed but MQTT connection was not
324  *    // closed. Thus, need to close both MQTT and socket connections.
325  *    status = MQTT_Disconnect( &( mqttAgentContext.mqttContext ) );
326  *    assert( status == MQTTSuccess );
327  *    Platform_DisconnectNetwork( mqttAgentContext.mqttContext.transportInterface.pNetworkContext );
328  * }
329  * else
330  * {
331  *     // Handle error.
332  * }
333  *
334  * @endcode
335  */
336 /* @[declare_mqtt_agent_commandloop] */
337 MQTTStatus_t MQTTAgent_CommandLoop( MQTTAgentContext_t * pMqttAgentContext );
338 /* @[declare_mqtt_agent_commandloop] */
339 
340 /**
341  * @brief Resume a session by resending publishes if a session is present in
342  * the broker, or clear state information if not.
343  *
344  * @param[in] pMqttAgentContext The MQTT agent to use.
345  * @param[in] sessionPresent The session present flag from the broker.
346  *
347  * @note This function is NOT thread-safe and should only be called
348  * from the context of the task responsible for #MQTTAgent_CommandLoop.
349  *
350  * @return #MQTTSuccess if it succeeds in resending publishes, else an
351  * appropriate error code from `MQTT_Publish()`
352  *
353  * <b>Example</b>
354  * @code{c}
355  *
356  * // Variables used in this example.
357  * MQTTStatus_t status;
358  * MQTTAgentContext_t mqttAgentContext;
359  * MQTTConnectInfo_t connectInfo = { 0 };
360  * MQTTPublishInfo_t willInfo = { 0 };
361  * bool sessionPresent;
362  *
363  * // The example assumes that all variables have been filled with
364  * // data for the MQTT_Connect call
365  * // Refer to the MQTT_Connect API for a more detailed example.
366  *
367  * // Attempt to resume session with the broker.
368  * status = MQTT_Connect( &( mqttAgentContext.mqttContext ), &connectInfo, &willInfo, 100, &sessionPresent )
369  *
370  * if( status == MQTTSuccess )
371  * {
372  *     // Process the session present status sent by the broker.
373  *     status = MQTTAgent_ResumeSession( &mqttAgentContext, sessionPresent );
374  * }
375  * @endcode
376  */
377 /* @[declare_mqtt_agent_resumesession] */
378 MQTTStatus_t MQTTAgent_ResumeSession( MQTTAgentContext_t * pMqttAgentContext,
379                                       bool sessionPresent );
380 /* @[declare_mqtt_agent_resumesession] */
381 
382 /**
383  * @brief Cancel all enqueued commands and those awaiting acknowledgment
384  * while the command loop is not running.
385  *
386  * Canceled commands will be terminated with return code #MQTTRecvFailed.
387  *
388  * @param[in] pMqttAgentContext The MQTT agent to use.
389  *
390  * @note This function is NOT thread-safe and should only be called
391  * from the context of the task responsible for #MQTTAgent_CommandLoop.
392  *
393  * @return #MQTTBadParameter if an invalid context is given, else #MQTTSuccess.
394  *
395  * <b>Example</b>
396  * @code{c}
397  *
398  * // Variables used in this example.
399  * MQTTStatus_t status;
400  * MQTTAgentContext_t mqttAgentContext;
401  *
402  * status = MQTTAgent_CommandLoop( &mqttAgentContext );
403  *
404  * //An error was returned, but reconnection is not desired. Cancel all commands
405  * //that are in the queue or awaiting an acknowledgment.
406  * if( status != MQTTSuccess )
407  * {
408  *    //Cancel commands so any completion callbacks will be invoked.
409  *    status = MQTTAgent_CancelAll( &mqttAgentContext );
410  * }
411  *
412  * Platform_DisconnectNetwork( mqttAgentContext.mqttContext.transportInterface.pNetworkContext );
413  *
414  * @endcode
415  */
416 /* @[declare_mqtt_agent_cancelall] */
417 MQTTStatus_t MQTTAgent_CancelAll( MQTTAgentContext_t * pMqttAgentContext );
418 /* @[declare_mqtt_agent_cancelall] */
419 
420 /**
421  * @brief Add a command to call MQTT_Subscribe() for an MQTT connection.
422  *
423  * @param[in] pMqttAgentContext The MQTT agent to use.
424  * @param[in] pSubscriptionArgs Struct describing topic to subscribe to.
425  * @param[in] pCommandInfo The information pertaining to the command, including:
426  *  - cmdCompleteCallback Optional callback to invoke when the command completes.
427  *  - pCmdCompleteCallbackContext Optional completion callback context.
428  *  - blockTimeMs The maximum amount of time in milliseconds to wait for the
429  *    command to be posted to the MQTT agent, should the agent's event queue
430  *    be full. Tasks wait in the Blocked state so don't use any CPU time.
431  *
432  * @note The context passed to the callback through pCmdContext member of
433  * @p pCommandInfo parameter MUST remain in scope at least until the callback
434  * has been executed by the agent task.
435  *
436  * @return #MQTTSuccess if the command was posted to the MQTT agent's event queue.
437  * Otherwise an enumerated error code.
438  *
439  * <b>Example</b>
440  * @code{c}
441  *
442  * // Variables used in this example.
443  * MQTTAgentContext_t agentContext;
444  * MQTTStatus_t status;
445  * MQTTAgentCommandInfo_t commandInfo = { 0 };
446  * MQTTSubscribeInfo_t subscribeInfo = { 0 };
447  * MQTTAgentSubscribeArgs_t subscribeArgs = { 0 };
448  *
449  * // Function for command complete callback.
450  * void subscribeCmdCompleteCb( MQTTAgentCommandContext_t * pCmdCallbackContext,
451  *                              MQTTAgentReturnInfo_t * pReturnInfo );
452  *
453  * // Fill the command information.
454  * commandInfo.CmdCompleteCallback = subscribeCmdCompleteCb;
455  * commandInfo.blockTimeMs = 500;
456  *
457  * // Fill the information for topic filters to subscribe to.
458  * subscribeInfo.qos = Qos1;
459  * subscribeInfo.pTopicFilter = "/foo/bar";
460  * subscribeInfo.topicFilterLength = strlen("/foo/bar");
461  * subscribeArgs.pSubscribeInfo = &subscribeInfo;
462  * subscribeArgs.numSubscriptions = 1U;
463  *
464  * status = MQTTAgent_Subscribe( &agentContext, &subscribeArgs, &commandInfo );
465  *
466  * if( status == MQTTSuccess )
467  * {
468  *   // Command to send subscribe request to the server has been queued. Notification
469  *   // about completion of the subscribe operation will be notified to application
470  *   // through invocation of subscribeCmdCompleteCb().
471  * }
472  *
473  * @endcode
474  */
475 /* @[declare_mqtt_agent_subscribe] */
476 MQTTStatus_t MQTTAgent_Subscribe( const MQTTAgentContext_t * pMqttAgentContext,
477                                   MQTTAgentSubscribeArgs_t * pSubscriptionArgs,
478                                   const MQTTAgentCommandInfo_t * pCommandInfo );
479 /* @[declare_mqtt_agent_subscribe] */
480 
481 /**
482  * @brief Add a command to call MQTT_Unsubscribe() for an MQTT connection.
483  *
484  * @param[in] pMqttAgentContext The MQTT agent to use.
485  * @param[in] pSubscriptionArgs List of topics to unsubscribe from.
486  * @param[in] pCommandInfo The information pertaining to the command, including:
487  *  - cmdCompleteCallback Optional callback to invoke when the command completes.
488  *  - pCmdCompleteCallbackContext Optional completion callback context.
489  *  - blockTimeMs The maximum amount of time in milliseconds to wait for the
490  *    command to be posted to the MQTT agent, should the agent's event queue
491  *    be full. Tasks wait in the Blocked state so don't use any CPU time.
492  *
493  * @note The context passed to the callback through pCmdContext member of
494  * @p pCommandInfo parameter MUST remain in scope at least until the callback
495  * has been executed by the agent task.
496  *
497  * @return #MQTTSuccess if the command was posted to the MQTT agent's event queue.
498  * Otherwise an enumerated error code.
499  *
500  * <b>Example</b>
501  * @code{c}
502  *
503  * // Variables used in this example.
504  * MQTTAgentContext_t agentContext;
505  * MQTTStatus_t status;
506  * MQTTAgentCommandInfo_t commandInfo = { 0 };
507  * MQTTSubscribeInfo_t unsubscribeInfo = { 0 };
508  * MQTTAgentSubscribeArgs_t unsubscribeArgs = { 0 };
509  *
510  * // Function for command complete callback.
511  * void unsubscribeCmdCompleteCb( MQTTAgentCommandContext_t * pCmdCallbackContext,
512  *                                MQTTAgentReturnInfo_t * pReturnInfo );
513  *
514  * // Fill the command information.
515  * commandInfo.cmdCompleteCallback = unsubscribeCmdCompleteCb;
516  * commandInfo.blockTimeMs = 500;
517  *
518  * // Fill the information for topics to unsubscribe from.
519  * unsubscribeInfo.pTopicFilter = "/foo/bar";
520  * unsubscribeInfo.topicFilterLength = strlen("/foo/bar");
521  * unsubscribeArgs.pSubscribeInfo = &unsubscribeInfo;
522  * unsubscribeArgs.numSubscriptions = 1U;
523  *
524  * status = MQTTAgent_Unsubscribe( &agentContext, &unsubscribeArgs, &commandInfo );
525  *
526  * if( status == MQTTSuccess )
527  * {
528  *   // Command to send Unsubscribe request to the server has been queued. Notification
529  *   // about completion of the Unsubscribe operation will be notified to application
530  *   // through invocation of unsubscribeCompleteCb().
531  * }
532  *
533  * @endcode
534  */
535 /* @[declare_mqtt_agent_unsubscribe] */
536 MQTTStatus_t MQTTAgent_Unsubscribe( const MQTTAgentContext_t * pMqttAgentContext,
537                                     MQTTAgentSubscribeArgs_t * pSubscriptionArgs,
538                                     const MQTTAgentCommandInfo_t * pCommandInfo );
539 /* @[declare_mqtt_agent_unsubscribe] */
540 
541 /**
542  * @brief Add a command to call MQTT_Publish() for an MQTT connection.
543  *
544  * @param[in] pMqttAgentContext The MQTT agent to use.
545  * @param[in] pPublishInfo MQTT PUBLISH information.
546  * @param[in] pCommandInfo The information pertaining to the command, including:
547  *  - cmdCompleteCallback Optional callback to invoke when the command completes.
548  *  - pCmdCompleteCallbackContext Optional completion callback context.
549  *  - blockTimeMs The maximum amount of time in milliseconds to wait for the
550  *    command to be posted to the MQTT agent, should the agent's event queue
551  *    be full. Tasks wait in the Blocked state so don't use any CPU time.
552  *
553  * @note The context passed to the callback through pCmdContext member of
554  * @p pCommandInfo parameter MUST remain in scope at least until the callback
555  * has been executed by the agent task.
556  *
557  * @return #MQTTSuccess if the command was posted to the MQTT agent's event queue.
558  * Otherwise an enumerated error code.
559  *
560  * <b>Example</b>
561  * @code{c}
562  *
563  * // Variables used in this example.
564  * MQTTAgentContext_t agentContext;
565  * MQTTStatus_t status;
566  * MQTTAgentCommandInfo_t commandInfo = { 0 };
567  * MQTTPublishInfo_t publishInfo = { 0 };
568  *
569  * // Function for command complete callback.
570  * void publishCmdCompleteCb( MQTTAgentCommandContext_t * pCmdCallbackContext,
571  *                            MQTTAgentReturnInfo_t * pReturnInfo );
572  *
573  * // Fill the command information.
574  * commandInfo.cmdCompleteCallback = publishCmdCompleteCb;
575  * commandInfo.blockTimeMs = 500;
576  *
577  * // Fill the information for publish operation.
578  * publishInfo.qos = MQTTQoS1;
579  * publishInfo.pTopicName = "/some/topic/name";
580  * publishInfo.topicNameLength = strlen( publishInfo.pTopicName );
581  * publishInfo.pPayload = "Hello World!";
582  * publishInfo.payloadLength = strlen( "Hello World!" );
583  *
584  * status = MQTTAgent_Publish( &agentContext, &publishInfo, &commandInfo );
585  *
586  * if( status == MQTTSuccess )
587  * {
588  *    // Command to publish message to broker has been queued.
589  *    // The event of publish operation completion will be notified with
590  *    // the invocation of the publishCmdCompleteCb().
591  * }
592  *
593  * @endcode
594  */
595 /* @[declare_mqtt_agent_publish] */
596 MQTTStatus_t MQTTAgent_Publish( const MQTTAgentContext_t * pMqttAgentContext,
597                                 MQTTPublishInfo_t * pPublishInfo,
598                                 const MQTTAgentCommandInfo_t * pCommandInfo );
599 /* @[declare_mqtt_agent_publish] */
600 
601 /**
602  * @brief Send a message to the MQTT agent purely to trigger an iteration of its loop,
603  * which will result in a call to MQTT_ProcessLoop().  This function can be used to
604  * wake the MQTT agent task when it is known data may be available on the connected
605  * socket.
606  *
607  * @param[in] pMqttAgentContext The MQTT agent to use.
608  * @param[in] pCommandInfo The information pertaining to the command, including:
609  *  - cmdCompleteCallback Optional callback to invoke when the command completes.
610  *  - pCmdCompleteCallbackContext Optional completion callback context.
611  *  - blockTimeMs The maximum amount of time in milliseconds to wait for the
612  *    command to be posted to the MQTT agent, should the agent's event queue
613  *    be full. Tasks wait in the Blocked state so don't use any CPU time.
614  *
615  * @return #MQTTSuccess if the command was posted to the MQTT agent's event queue.
616  * Otherwise an enumerated error code.
617  *
618  * <b>Example</b>
619  * @code{c}
620  *
621  * // Variables used in this example.
622  * MQTTAgentContext_t agentContext;
623  * MQTTStatus_t status;
624  * MQTTAgentCommandInfo_t commandInfo = { 0 };
625  *
626  * // Function for command complete callback.
627  * void cmdCompleteCb( MQTTAgentCommandContext_t * pCmdCallbackContext,
628  *                     MQTTAgentReturnInfo_t * pReturnInfo );
629  *
630  * // Fill the command information.
631  * commandInfo.cmdCompleteCallback = cmdCompleteCb;
632  * commandInfo.blockTimeMs = 500;
633  *
634  * status = MQTTAgent_ProcessLoop( &agentContext, &commandInfo );
635  *
636  * if( status == MQTTSuccess )
637  * {
638  *    // Command to call MQTT_ProcessLoop() has been queued.
639  *    // After processing the command, if an incoming publish is received,
640  *    // the event will be notified with invocation of the incoming publish
641  *    // callback configured in the agent context.
642  * }
643  *
644  * @endcode
645  */
646 /* @[declare_mqtt_agent_processloop] */
647 MQTTStatus_t MQTTAgent_ProcessLoop( const MQTTAgentContext_t * pMqttAgentContext,
648                                     const MQTTAgentCommandInfo_t * pCommandInfo );
649 /* @[declare_mqtt_agent_processloop] */
650 
651 /**
652  * @brief Add a command to call MQTT_Ping() for an MQTT connection.
653  *
654  * @note This API function ONLY enqueues a command to send a ping request to the server,
655  * and DOES NOT wait for a ping response to be received from the server. To detect whether
656  * a Ping Response, has not been received from the server, the @ref MQTTAgent_CommandLoop
657  * function SHOULD be used, which returns the #MQTTKeepAliveTimeout return code on a ping
658  * response (or keep-alive) timeout.
659  *
660  * @param[in] pMqttAgentContext The MQTT agent to use.
661  * @param[in] pCommandInfo The information pertaining to the command, including:
662  *  - cmdCompleteCallback Optional callback to invoke when the command completes.
663  *  - pCmdCompleteCallbackContext Optional completion callback context.
664  *  - blockTimeMs The maximum amount of time in milliseconds to wait for the
665  *    command to be posted to the MQTT agent, should the agent's event queue
666  *    be full. Tasks wait in the Blocked state so don't use any CPU time.
667  *
668  * @note The context passed to the callback through pCmdContext member of
669  * @p pCommandInfo parameter MUST remain in scope at least until the callback
670  * has been executed by the agent task.
671  *
672  * @return #MQTTSuccess if the command was posted to the MQTT agent's event queue.
673  * Otherwise an enumerated error code.
674  *
675  * <b>Example</b>
676  * @code{c}
677  *
678  * // Variables used in this example.
679  * MQTTAgentContext_t agentContext;
680  * MQTTStatus_t status;
681  * MQTTAgentCommandInfo_t commandInfo = { 0 };
682  *
683  * // Function for command complete callback.
684  * void pingRequestCompleteCb( MQTTAgentCommandContext_t * pCmdCallbackContext,
685  *                             MQTTAgentReturnInfo_t * pReturnInfo );
686  *
687  * // Fill the command information.
688  * commandInfo.cmdCompleteCallback = pingRequestCompleteCb;
689  * commandInfo.blockTimeMs = 500;
690  *
691  * status = MQTTAgent_Ping( &agentContext, &commandInfo );
692  *
693  * if( status == MQTTSuccess )
694  * {
695  *   // Command for sending request has been queued. Application can
696  *   // handle keep-alive timeout if detected through return value of
697  *   // MQTTAgent_CommandLoop in the task running the agent.
698  * }
699  *
700  * @endcode
701  */
702 /* @[declare_mqtt_agent_ping] */
703 MQTTStatus_t MQTTAgent_Ping( const MQTTAgentContext_t * pMqttAgentContext,
704                              const MQTTAgentCommandInfo_t * pCommandInfo );
705 /* @[declare_mqtt_agent_ping] */
706 
707 /**
708  * @brief Add a command to call MQTT_Connect() for an MQTT connection. If a session
709  * is resumed with the broker, it will also resend the necessary QoS1/2 publishes.
710  *
711  * @note The MQTTAgent_Connect function is provided to give a thread safe equivalent
712  * to the MQTT_Connect API. However, it is RECOMMENDED that instead of the application
713  * tasks (i.e. tasks other than the agent task), the agent be responsible for creating
714  * the MQTT connection (by calling MQTT_Connect) before starting the command loop (with
715  * the MQTTAgent_CommandLoop() call). In that case, the agent SHOULD also be responsible
716  * for disconnecting the MQTT connection after the command loop has terminated (through
717  * an MQTTAgent_Terminate() call from an application task).
718  *
719  * @param[in] pMqttAgentContext The MQTT agent to use.
720  * @param[in, out] pConnectArgs Struct holding args for MQTT_Connect(). On a successful
721  * connection after the command is processed, the sessionPresent member will be filled
722  * to indicate whether the broker resumed an existing session.
723  * @param[in] pCommandInfo The information pertaining to the command, including:
724  *  - cmdCompleteCallback Optional callback to invoke when the command completes.
725  *  - pCmdCompleteCallbackContext Optional completion callback context.
726  *  - blockTimeMs The maximum amount of time in milliseconds to wait for the
727  *    command to be posted to the MQTT agent, should the agent's event queue
728  *    be full. Tasks wait in the Blocked state so don't use any CPU time.
729  *
730  * @note The context passed to the callback through pCmdContext member of
731  * @p pCommandInfo parameter MUST remain in scope at least until the callback
732  * has been executed by the agent task.
733  *
734  * @return #MQTTSuccess if the command was posted to the MQTT agent's event queue.
735  * Otherwise an enumerated error code.
736  *
737  * <b>Example</b>
738  * @code{c}
739  *
740  * // Variables used in this example.
741  * MQTTAgentContext_t agentContext;
742  * MQTTStatus_t status;
743  * MQTTConnectInfo_t connectInfo = { 0 };
744  * MQTTPublishInfo_t willInfo = { 0 };
745  * MQTTAgentConnectArgs_t connectionArgs;
746  * MQTTAgentCommandInfo_t commandInfo = { 0 };
747  *
748  * // True for creating a new session with broker, false if we want to resume an old one.
749  * connectInfo.cleanSession = true;
750  * // Client ID must be unique to broker. This field is required.
751  * connectInfo.pClientIdentifier = "someClientID";
752  * connectInfo.clientIdentifierLength = strlen( connectInfo.pClientIdentifier );
753  *
754  * // Value for keep alive.
755  * connectInfo.keepAliveSeconds = 60;
756  * // The following fields are optional.
757  * // Optional username and password.
758  * connectInfo.pUserName = "someUserName";
759  * connectInfo.userNameLength = strlen( connectInfo.pUserName );
760  * connectInfo.pPassword = "somePassword";
761  * connectInfo.passwordLength = strlen( connectInfo.pPassword );
762  *
763  * // The last will and testament is optional, it will be published by the broker
764  * // should this client disconnect without sending a DISCONNECT packet.
765  * willInfo.qos = MQTTQoS0;
766  * willInfo.pTopicName = "/lwt/topic/name";
767  * willInfo.topicNameLength = strlen( willInfo.pTopicName );
768  * willInfo.pPayload = "LWT Message";
769  * willInfo.payloadLength = strlen( "LWT Message" );
770  *
771  * // Fill the MQTTAgentConnectArgs_t structure.
772  * connectArgs.pConnectInfo = &connectInfo;
773  * connectArgs.pWillInfo = &willInfo;
774  * // Time to block for CONNACK response when command is processed.
775  * connectArgs.timeoutMs = 500;
776  *
777  * // Function for command complete callback.
778  * void connectCmdCallback( MQTTAgentCommandContext_t * pCmdCallbackContext,
779  *                          MQTTAgentReturnInfo_t * pReturnInfo );
780  *
781  * // Fill the command information.
782  * commandInfo.cmdCompleteCallback = connectCmdCallback;
783  * commandInfo.blockTimeMs = 500;
784  *
785  * status = MQTTAgent_Connect( &agentContext, &connectArgs, &commandInfo );
786  *
787  * if( status == MQTTSuccess )
788  * {
789  *   // Command for creating the MQTT connection has been queued.
790  *   // The MQTT connection event will be notified through the
791  *   // invocation of connectCmdCallback().
792  * }
793  * @endcode
794  */
795 /* @[declare_mqtt_agent_connect] */
796 MQTTStatus_t MQTTAgent_Connect( const MQTTAgentContext_t * pMqttAgentContext,
797                                 MQTTAgentConnectArgs_t * pConnectArgs,
798                                 const MQTTAgentCommandInfo_t * pCommandInfo );
799 /* @[declare_mqtt_agent_connect] */
800 
801 /**
802  * @brief Add a command to disconnect an MQTT connection.
803  *
804  * @note #MQTTAgent_CommandLoop will return after processing a #DISCONNECT
805  * command to allow the network connection to be disconnected. However, any
806  * pending commands in the queue, as well as those waiting for an acknowledgment,
807  * will NOT be terminated.
808  *
809  * @note The MQTTAgent_Disconnect function is provided to give a thread safe
810  * equivalent to the MQTT_Disconnect API. However, if the agent task is responsible
811  * for creating the MQTT connection (before calling MQTTAgent_CommandLoop()), then
812  * it is RECOMMENDED that an application task (i.e. a task other than the agent task)
813  * use MQTTAgent_Terminate to terminate the command loop in the agent, and the agent
814  * task be responsible for disconnecting the MQTT connection.
815  *
816  * @param[in] pMqttAgentContext The MQTT agent to use.
817  * @param[in] pCommandInfo The information pertaining to the command, including:
818  *  - cmdCompleteCallback Optional callback to invoke when the command completes.
819  *  - pCmdCompleteCallbackContext Optional completion callback context.
820  *  - blockTimeMs The maximum amount of time in milliseconds to wait for the
821  *    command to be posted to the MQTT agent, should the agent's event queue
822  *    be full. Tasks wait in the Blocked state so don't use any CPU time.
823  *
824  * @note The context passed to the callback through pCmdContext member of
825  * @p pCommandInfo parameter MUST remain in scope at least until the callback
826  * has been executed by the agent task.
827  *
828  * @return #MQTTSuccess if the command was posted to the MQTT agent's event queue.
829  * Otherwise an enumerated error code.
830  *
831  * <b>Example</b>
832  * @code{c}
833  *
834  * // Variables used in this example.
835  * MQTTAgentContext_t agentContext;
836  * MQTTStatus_t status;
837  * MQTTAgentCommandInfo_t commandInfo = { 0 };
838  *
839  * // Function for command complete callback.
840  * void disconnectCmdCallback( MQTTAgentCommandContext_t * pCmdCallbackContext,
841  *                             MQTTAgentReturnInfo_t * pReturnInfo );
842  *
843  * // Fill the command information.
844  * commandInfo.cmdCompleteCallback = disconnectCmdCallback;
845  * commandInfo.blockTimeMs = 500;
846  *
847  * status = MQTTAgent_Disconnect( &agentContext, &commandInfo );
848  *
849  * if( status == MQTTSuccess )
850  * {
851  *   // Command for closing the MQTT connection has been queued.
852  *   // The MQTT disconnection event will be notified through the
853  *   // invocation of disconnectCmdCallback().
854  * }
855  *
856  * @endcode
857  */
858 /* @[declare_mqtt_agent_disconnect] */
859 MQTTStatus_t MQTTAgent_Disconnect( const MQTTAgentContext_t * pMqttAgentContext,
860                                    const MQTTAgentCommandInfo_t * pCommandInfo );
861 /* @[declare_mqtt_agent_disconnect] */
862 
863 /**
864  * @brief Add a termination command to the command queue.
865  *
866  * On command loop termination, all pending commands in the queue, as well
867  * as those waiting for an acknowledgment, will be terminated with error code
868  * #MQTTRecvFailed.
869  *
870  * @note Commands may still be posted to the command queue after #MQTTAgent_CommandLoop
871  * has returned. It is the responsibility of the application to cancel any
872  * commands that are posted while the command loop is not running, such as by
873  * invoking #MQTTAgent_CancelAll.
874  *
875  * @note We RECOMMEND that this function is used from application task(s),
876  * that is a task not running the agent, to terminate the agent loop instead
877  * of calling MQTTAgent_Disconnect, so that the logic for creating and closing
878  * MQTT connection is owned by the agent task.
879  *
880  * @param[in] pMqttAgentContext The MQTT agent to use.
881  * @param[in] pCommandInfo The information pertaining to the command, including:
882  *  - cmdCompleteCallback Optional callback to invoke when the command completes.
883  *  - pCmdCompleteCallbackContext Optional completion callback context.
884  *  - blockTimeMs The maximum amount of time in milliseconds to wait for the
885  *    command to be posted to the MQTT agent, should the agent's event queue
886  *    be full. Tasks wait in the Blocked state so don't use any CPU time.
887  *
888  * @note The context passed to the callback through pCmdContext member of
889  * @p pCommandInfo parameter MUST remain in scope at least until the callback
890  * has been executed by the agent task.
891  *
892  * @return #MQTTSuccess if the command was posted to the MQTT agent's event queue.
893  * Otherwise an enumerated error code.
894  *
895  * <b>Example</b>
896  * @code{c}
897  *
898  * // Variables used in this example.
899  * MQTTAgentContext_t agentContext;
900  * MQTTStatus_t status;
901  * MQTTAgentCommandInfo_t commandInfo = { 0 };
902  *
903  * // Function for command complete callback.
904  * void terminateCallback( MQTTAgentCommandContext_t * pCmdCallbackContext,
905  *                         MQTTAgentReturnInfo_t * pReturnInfo );
906  *
907  * // Fill the command information.
908  * commandInfo.cmdCompleteCallback = terminateCallback;
909  * commandInfo.blockTimeMs = 500;
910  *
911  * status = MQTTAgent_Terminate( &agentContext, &commandInfo );
912  *
913  * if( status == MQTTSuccess )
914  * {
915  *   // Command to terminate the agent loop has been queued.
916  * }
917  *
918  * @endcode
919  *
920  */
921 /* @[declare_mqtt_agent_terminate] */
922 MQTTStatus_t MQTTAgent_Terminate( const MQTTAgentContext_t * pMqttAgentContext,
923                                   const MQTTAgentCommandInfo_t * pCommandInfo );
924 /* @[declare_mqtt_agent_terminate] */
925 
926 /* *INDENT-OFF* */
927 #ifdef __cplusplus
928     }
929 #endif
930 /* *INDENT-ON* */
931 
932 #endif /* CORE_MQTT_AGENT_H */
933