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