/*
* Amazon FreeRTOS
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file aws_shadow.h
* @brief Shadow API configuration, functions, and parameter structs.
*/
#ifndef _AWS_SHADOW_H_
#define _AWS_SHADOW_H_
#include "FreeRTOS.h"
#include "aws_mqtt_agent.h"
/**
* @brief The handle of a Shadow Client.
*/
typedef void * ShadowClientHandle_t;
/**
* @brief Return values of Shadow API functions.
*
* Negative values indicate jsmn (JSON parser) errors, and @c 0 indicates
* success. Positive values indicate other errors. Values in the range of @c 400
* to @c 500 correspond to Shadow service rejection reasons.
*
* Refer to jsmn.h for jsmn errors.
*
* Refer to
* http://docs.aws.amazon.com/iot/latest/developerguide/thing-shadow-error-messages.html
* for Shadow service rejection reasons.
*/
#define eShadowJSMNPart ( -3 )
#define eShadowJSMNInval ( -2 )
#define eShadowJSMNNoMem ( -1 )
/** An operation was accepted by the Shadow service, and all subroutines
* completed successfully. */
#define eShadowSuccess ( 0 )
/** Timeout signifies that at least one of the API call's subroutines failed to
* complete within the given time. This error can usually be fixed by increasing
* the timeout parameter.
* @note
* - Timeout doesn't always imply rejection. An operation may still be accepted
* after a timeout. However, the Shadow Client will not notify of acceptance or
* rejection after a timeout.
* - If an update fails because of incorrect JSON syntax in the update document,
* the update API call will return this code instead of @c eShadowRejectedBadRequest
* and print an error message if #shadowENABLE_DEBUG_LOGS is @c 1. */
#define eShadowTimeout ( 1 )
/** Failure code; signifies that at least one subroutine failed to complete
* and did not time out. */
#define eShadowFailure ( 2 )
/** Indicates neither failure nor success. This value should never be returned
* by a Shadow API function, but is used internally. */
#define eShadowUnknown ( 3 )
/**
* @brief Shadow service rejection reasons. */
/** @{ */
#define eShadowRejectedBadRequest ( 400 )
#define eShadowRejectedUnauthorized ( 401 )
#define eShadowRejectedForbidden ( 403 )
#define eShadowRejectedNotFound ( 404 )
#define eShadowRejectedConflict ( 409 )
#define eShadowRejectedPayloadTooLarge ( 413 )
#define eShadowRejectedUnsupportedMediaType ( 415 )
#define eShadowRejectedTooManyRequests ( 429 )
#define eShadowRejectedInternalServerError ( 500 )
typedef int16_t ShadowReturnCode_t;
/** @} */
/**
* @brief Type of MQTT client in a new Shadow Client.
*
* The possible values of #ShadowCreateParams_t.xMQTTClientType; determines
* whether to initialize a shared or dedicated MQTT client.
* @note Only #eDedicatedMQTTClient is supported at this time.
*/
typedef enum ShadowMQTTClientType
{
/** A shared MQTT client that may be used for purposes other than Shadow
* Client. Currently unsupported. */
eSharedMQTTClient,
/** A dedicated MQTT client to be used only by Shadow Client. */
eDedicatedMQTTClient
} ShadowMQTTClientType_t;
/**
* @brief Parameters to pass into #SHADOW_ClientCreate.
*/
typedef struct ShadowCreateParams
{
/**
* @brief MQTT Client type.
*
* Whether the new Shadow Client will use a shared or dedicated MQTT Client.
* Currently, only #eDedicatedMQTTClient is supported.
* @see ShadowMQTTClientType. */
ShadowMQTTClientType_t xMQTTClientType;
/**
* @brief Handle of a shared MQTT client.
*
* If #ShadowCreateParams_t.xMQTTClientType is #eSharedMQTTClient, set this to
* the handle of the shared client. This member is ignored if
#ShadowCreateParams_t.xMQTTClientType is #eDedicatedMQTTClient. */
MQTTAgentHandle_t xMQTTClientHandle;
} ShadowCreateParams_t;
/**
* @brief Parameters for a Shadow API operation.
*
* Pass this struct as one of the arguments for #SHADOW_Update, #SHADOW_Get, or
* #SHADOW_Delete.
*/
typedef struct ShadowOperationParams
{
/** @brief Thing name of Shadow. */
const char * pcThingName;
/**
* @brief Input parameter for #SHADOW_Update; output parameter of #SHADOW_Get.
* - For #SHADOW_Update, set this to point to the Shadow update document.
* - For #SHADOW_Get, this is the output parameter pointing to a buffer which
* holds the Shadow document. If #SHADOW_Get fails, this will be set to NULL.
* - This member is ignored by #SHADOW_Delete. */
const char * pcData;
/**
* @brief Input parameter for #SHADOW_Update; output parameter of #SHADOW_Get.
* - For #SHADOW_Update, set this to length of the Shadow update document.
* - For #SHADOW_Get, this is the output parameter specifying the length of
* #ShadowOperationParams_t.pcData. If #SHADOW_Get fails, this will be set
* to @c 0.
* @note If the received Shadow document is longer than this value, the
* document will be truncated. A warning message will be printed if
* #shadowENABLE_DEBUG_LOGS is @c 1.
* - This member is ignored by #SHADOW_Delete. */
uint32_t ulDataLength;
/**
* @brief Output parameter of #SHADOW_Get.
* - This member is ignored by #SHADOW_Update.
* - For #SHADOW_Get, this is the output parameter for the MQTT Buffer Handle.
* This buffer must be returned to the MQTT Client after the user is done
* with the received document by calling #SHADOW_ReturnMQTTBuffer.
* - This member is ignored by #SHADOW_Delete. */
MQTTBufferHandle_t xBuffer;
/**
* @brief Controls whether topic subscriptions remain active after a Shadow
* operation completes.
*
* Allows the MQTT subscriptions of the operation to remain active if set
* to @c 1, saving time if the same operation is performed again. Set this
* value to @c 0 to deactivate the operation's MQTT subscriptions after the
* operation completes.
* @warning Users may be billed for extraneous messages received on an
* operation's MQTT topics. If other clients are publishing to the same topics,
* it is best to deactivate the subscriptions. */
uint8_t ucKeepSubscriptions;
/**
* @brief MQTT QoS when publishing from the Shadow Client @b to the Shadow Service.
* @note The Shadow services always publishes to the Shadow Client with QoS 1. */
MQTTQoS_t xQoS;
} ShadowOperationParams_t;
/**
* @brief Function signature of a callback function registered for /update/documents.
*
* @param in: Custom user data.
* @param pcThingName The Thing Name of the updated Shadow.
* @param pcUpdateDocument The update document, a JSON string.
* @param ulDocumentLength The length of the update document.
* @param xBuffer The MQTT buffer containing @p pcUpdateDocument. This buffer
* must eventually be returned by calling #SHADOW_ReturnMQTTBuffer if taken.
*
* @return
* - pdTRUE to take ownership of the MQTT buffer containing pcUpdateDocument
* - pdFALSE to leave pcUpdateDocument with the MQTT client. The MQTT client
* may overwrite pcUpdateDocument.
*
* @note Callback functions are called from the MQTT task.
* @warning
* - Do not make any blocking calls (including #SHADOW_Update, #SHADOW_Get, or
* #SHADOW_Delete) in a callback function!
* - The MQTT client does not guarantee that messages on /update/documents
* will be received in the order they were published. If updates are being
* performed frequently, it is possible to receive newer update documents
* before older ones.
*/
typedef BaseType_t ( * ShadowUpdatedCallback_t )( void * pvUserData,
const char * const pcThingName,
const char * const pcUpdateDocument,
uint32_t ulDocumentLength,
MQTTBufferHandle_t xBuffer );
/**
* @brief Function header of a callback function registered for /delete/accepted.
*
* @param in: Custom user data.
* @param pcThingName The Name of the Thing whose Shadow was deleted.
*
* @note Callback functions are called from the MQTT task.
* @warning Do not make any blocking calls (including #SHADOW_Update, #SHADOW_Get, or
* #SHADOW_Delete) in a callback function!
*/
typedef void ( * ShadowDeletedCallback_t )( void * pvUserData,
const char * const pcThingName );
/**
* @brief Function header of a callback function registered for /update/delta.
*
* @param in: Custom user data.
* @param pcThingName The Thing Name of the delta document.
* @param pcDeltaDocument The delta document, a JSON string.
* @param ulDocumentLength The length of the delta document.
* @param xBuffer The MQTT buffer containing @p pcDeltaDocument. This buffer
* must eventually be returned by calling #SHADOW_ReturnMQTTBuffer if taken.
*
* @return
* - pdTRUE to take ownership of the MQTT buffer containing pcDeltaDocument
* - pdFALSE to leave pcDeltaDocument with the MQTT client. The MQTT client
* may overwrite pcDeltaDocument.
*
* @note Callback functions are called from the MQTT task.
* @warning
* - Do not make any blocking calls (including #SHADOW_Update, #SHADOW_Get, or
* #SHADOW_Delete) in a callback function!
* - The MQTT client does not guarantee that messages on /update/delta
* will be received in the order they were published. If updates are being
* performed frequently, it is possible to receive newer delta documents
* before older ones.
*/
typedef BaseType_t ( * ShadowDeltaCallback_t )( void * pvUserData,
const char * const pcThingName,
const char * const pcDeltaDocument,
uint32_t ulDocumentLength,
MQTTBufferHandle_t xBuffer );
/**
* @brief Parameters to #SHADOW_RegisterCallbacks.
*/
typedef struct ShadowCallbackParams
{
/** @brief Thing Name for which callbacks are registered. */
const char * pcThingName;
/**
* @brief Called to notify users that a Thing Shadow has been updated.
*
* Callback for a message on /update/documents. Set to NULL for no callback.
* @note This function @b will be called if the same Shadow Client that registered
* the callback function updated the Thing Shadow. */
ShadowUpdatedCallback_t xShadowUpdatedCallback;
/**
* @brief Called to notify users that @b another client has deleted the Thing Shadow.
*
* Callback for a message on /delete/accepted. Set to NULL for no callback.
* @note This function will not be called if the same Shadow Client that
* registered the callback function deleted the Thing Shadow. */
ShadowDeletedCallback_t xShadowDeletedCallback;
/**
* @brief Called to notify users that a delta document has been generated.
*
* Callback for a message on /delete/accepted. Set to NULL for no callback.
* @note This function @b will be called whenever a delta document is generated,
* regardless of which client performed an update. */
ShadowDeltaCallback_t xShadowDeltaCallback;
} ShadowCallbackParams_t;
/**
* @brief Create a new Shadow Client.
*
* @param[out] pxShadowClientHandle Output parameter for the handle of the
* newly-created Shadow Client. Only valid if the return code is #eShadowSuccess.
* @param[in] pxShadowCreateParams Pointer to a #ShadowCreateParams struct.
* @param[in] xTimeoutTicks Number of ticks this function may block before
* timeout.
*
* @return #ShadowReturnCode. The value of output parameter pxShadowClientHandle
* is valid only if the return code is #eShadowSuccess.
*
* @note
* - If xTimeoutTicks is insufficient time for initialization, this function
* will timeout and stop Shadow Client initialization. However, this function
* may block for up to (xTimeoutTicks + #shadowCLEANUP_TIME_MS) time as it
* cleans up a partially-initialized Shadow Client.
*/
ShadowReturnCode_t SHADOW_ClientCreate( ShadowClientHandle_t * pxShadowClientHandle,
const ShadowCreateParams_t * const pxShadowCreateParams );
/**
* @brief Connect to the Shadow service.
*
* For a Shadow Client with a dedicated MQTT Client (#eDedicatedMQTTClient), calling
* this function is the only way to connect to the Shadow service. For a Shadow
* Client with a shared MQTT Client (#eSharedMQTTClient), calling this function is
* equivalent to calling @c MQTT_AGENT_Connect with the corresponding shared
* MQTT Client handle.
*
* @param[in] xShadowClientHandle Handle of Shadow Client to connect.
* @param[in] pxConnectParams Pointer to a @c TradstoneMQTTConnectParams_t struct.
* Note: ClientHandle should be at the top of user data passed in pxConnectParams
* @param[in] xTimeoutTicks Number of ticks this function may block before timeout.
*
* @return #ShadowReturnCode.
*/
ShadowReturnCode_t SHADOW_ClientConnect( ShadowClientHandle_t xShadowClientHandle,
MQTTAgentConnectParams_t * const pxConnectParams,
TickType_t xTimeoutTicks );
/**
* @brief Disconnect from the Shadow service.
*
* For a Shadow Client with a dedicated MQTT Client (#eDedicatedMQTTClient), calling
* this function is the only way to disconnect from the Shadow service. For a Shadow
* Client with a shared MQTT Client (#eSharedMQTTClient), calling this function is
* equivalent to calling @c MQTT_AGENT_Disconnect with the corresponding shared
* MQTT Client handle.
*
* @param[in] xShadowClientHandle Handle of Shadow Client to disconnect.
*
* @return Unless #shadowCLEANUP_TIME_MS is insufficient to disconnect a Shadow
* Client, this function always returns #eShadowSuccess.
*/
ShadowReturnCode_t SHADOW_ClientDisconnect( ShadowClientHandle_t xShadowClientHandle );
/**
* @brief Free resources used by a Shadow Client.
*
* @param[in] xShadowClientHandle Handle of Shadow Client to be deleted.
*
* @return #ShadowReturnCode.
*
* @warning Do not call while another operation is in progress on the Shadow Client.
* A Shadow Client must be re-initialized after this function completes if it is
* to be used again.
*/
ShadowReturnCode_t SHADOW_ClientDelete( ShadowClientHandle_t xShadowClientHandle );
/**
* @brief Update a Thing Shadow.
*
* @param[in] xShadowClientHandle Handle of Shadow Client to use for update.
* @param[in] pxUpdateParams A pointer to a #ShadowOperationParams struct.
* @param[in] xTimeoutTicks Number of ticks this function may block before timeout.
*
* @return #ShadowReturnCode.
*
* @note
* - If xTimeoutTicks is insufficient time for the update, this function will
* timeout and stop the update. However, this function may block for up to
* (xTimeoutTicks + #shadowCLEANUP_TIME_MS) time as it cleans up subscriptions.
* - A timeout does not always mean that the update failed. The Shadow Service
* may still accept an update after this function times out. However, the user
* will not be notified if acceptance occurs after a timeout. The user may
* intentionally set a short timeout if the result of the update isn't relevant,
* but the timeout must still be long enough for the update to be published.
*/
ShadowReturnCode_t SHADOW_Update( ShadowClientHandle_t xShadowClientHandle,
ShadowOperationParams_t * const pxUpdateParams,
TickType_t xTimeoutTicks );
/**
* @brief Get a Thing Shadow from the cloud.
*
* @param[in] xShadowClientHandle Handle of Shadow Client to use for get.
* @param pxGetParams A pointer to a #ShadowOperationParams struct. This is used
* as both an input and output parameter.
* @param[in] xTimeoutTicks Number of ticks this function may block before timeout.
*
* @return #ShadowReturnCode.
*
* @note
* - If xTimeoutTicks is insufficient time for the get, this function will
* timeout and stop the get. However, this function may block for up to
* (xTimeoutTicks + #shadowCLEANUP_TIME_MS) time as it cleans up subscriptions.
* - Documents received from the cloud after a timeout are ignored.
* - A call to #SHADOW_ReturnMQTTBuffer should follow a call to #SHADOW_Get to
* return the MQTT Buffer taken by #SHADOW_Get. #ShadowOperationParams_t.xBuffer
* should be passed as @p xBufferHandle.
*/
ShadowReturnCode_t SHADOW_Get( ShadowClientHandle_t xShadowClientHandle,
ShadowOperationParams_t * const pxGetParams,
TickType_t xTimeoutTicks );
/**
* @brief Delete a Thing Shadow in the cloud.
*
* @param[in] xShadowClientHandle Handle of Shadow Client to use for delete.
* @param[in] pxDeleteParams A pointer to a #ShadowOperationParams struct.
* @param[in] xTimeoutTicks Number of ticks this function may block before timeout.
*
* @return #ShadowReturnCode.
*
* @note
* - If xTimeoutTicks is insufficient time for the delete, this function will
* timeout and stop the delete. However, this function may block for up to
* (xTimeoutTicks + #shadowCLEANUP_TIME_MS) time as it cleans up subscriptions.
* - A timeout does not always mean that the delete failed. The Shadow Service
* may still accept the delete after this function times out. However, the user
* will not be notified if acceptance occurs after a timeout. The user may
* intentionally set a short timeout if the result of the delete isn't relevant,
* but the timeout must still be long enough for the delete to be published.
*/
ShadowReturnCode_t SHADOW_Delete( ShadowClientHandle_t xShadowClientHandle,
ShadowOperationParams_t * const pxDeleteParams,
TickType_t xTimeoutTicks );
/**
* @brief Register callback functions.
*
* @param[in] xShadowClientHandle Handle of Shadow Client to use for registering callbacks.
* @param[in] pxCallbackParams A pointer to a #ShadowCallbackParams struct.
* @param[in] xTimeoutTicks Number of ticks this function may block before timeout.
*
* @return
* - #eShadowSuccess if all callbacks registered successfully.
* - #eShadowFailure if the Shadow Client failed to subscribe to at least one
* callback topic and did not time out.
* - #eShadowTimeout if the Shadow Client timed out when subscribing to at least
* one callback topic.
*
* @note
* - This function will register as many callbacks as it can before xTimeoutTicks
* elapses.
* - Callbacks are registered in the order Updated, Deleted, Delta.
* - If a callback fails to register, this function will print a debug message if
* #shadowENABLE_DEBUG_LOGS is @c 1 and attempt to register the next callback.
*/
ShadowReturnCode_t SHADOW_RegisterCallbacks( ShadowClientHandle_t xShadowClientHandle,
ShadowCallbackParams_t * const pxCallbackParams,
TickType_t xTimeoutTicks );
/**
* @brief Return an MQTT Buffer to the MQTT client.
*
* For a Shadow Client with a dedicated MQTT Client (#eDedicatedMQTTClient), calling
* this function is the only way to return an MQTT Buffer. For a Shadow Client with
* a shared MQTT Client (#eSharedMQTTClient), calling this function is equivalent
* to calling @c MQTT_AGENT_ReturnBuffer with the corresponding shared MQTT
* Client handle.
*
* @param[in] xShadowClientHandle Handle of Shadow Client for MQTT Buffer return.
* @param[in] xBufferHandle Handle of MQTT Buffer to return.
*
* @return #ShadowReturnCode.
*
* @note
* - This function should be called after every #SHADOW_Get call to return the
* MQTT buffer taken by #SHADOW_Get. Otherwise, the MQTT client will run out
* of buffers after repeated calls to #SHADOW_Get.
* - This function should also be called to return buffers taken in callback
* functions #ShadowUpdatedCallback_t and #ShadowDeltaCallback_t.
*/
ShadowReturnCode_t SHADOW_ReturnMQTTBuffer( ShadowClientHandle_t xShadowClientHandle,
MQTTBufferHandle_t xBufferHandle );
#endif /* _AWS_SHADOW_H_ */