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