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