/* | |
* AWS IoT Shadow V2.1.0 | |
* Copyright (C) 2018 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. | |
*/ | |
/** | |
* @file aws_iot_shadow_api.c | |
* @brief Implements the user-facing functions of the Shadow library. | |
*/ | |
/* The config header is always included first. */ | |
#include "iot_config.h" | |
/* Standard includes. */ | |
#include <string.h> | |
/* Shadow internal include. */ | |
#include "private/aws_iot_shadow_internal.h" | |
/* Error handling include. */ | |
#include "iot_error.h" | |
/* Platform layer includes. */ | |
#include "platform/iot_threads.h" | |
/* MQTT include. */ | |
#include "iot_mqtt.h" | |
/* Validate Shadow configuration settings. */ | |
#if AWS_IOT_SHADOW_ENABLE_ASSERTS != 0 && AWS_IOT_SHADOW_ENABLE_ASSERTS != 1 | |
#error "AWS_IOT_SHADOW_ENABLE_ASSERTS must be 0 or 1." | |
#endif | |
#if AWS_IOT_SHADOW_DEFAULT_MQTT_TIMEOUT_MS <= 0 | |
#error "AWS_IOT_SHADOW_DEFAULT_MQTT_TIMEOUT_MS cannot be 0 or negative." | |
#endif | |
/*-----------------------------------------------------------*/ | |
/** | |
* @brief Check if the library is initialized. | |
* | |
* @return `true` if AwsIotShadow_Init was called; `false` otherwise. | |
*/ | |
static bool _checkInit( void ); | |
/** | |
* @brief Checks Thing Name and flags parameters passed to Shadow API functions. | |
* | |
* @param[in] type The Shadow API function type. | |
* @param[in] pThingName Thing Name passed to Shadow API function. | |
* @param[in] thingNameLength Length of `pThingName`. | |
* @param[in] flags Flags passed to Shadow API function. | |
* @param[in] pCallbackInfo Callback info passed to Shadow API function. | |
* @param[in] pOperation Operation reference pointer passed to Shadow API function. | |
* | |
* @return #AWS_IOT_SHADOW_SUCCESS or #AWS_IOT_SHADOW_BAD_PARAMETER. | |
*/ | |
static AwsIotShadowError_t _validateThingNameFlags( _shadowOperationType_t type, | |
const char * pThingName, | |
size_t thingNameLength, | |
uint32_t flags, | |
const AwsIotShadowCallbackInfo_t * pCallbackInfo, | |
const AwsIotShadowOperation_t * pOperation ); | |
/** | |
* @brief Checks document info parameter passed to Shadow API functions. | |
* | |
* @param[in] type The Shadow API function type. | |
* @param[in] flags Flags passed to Shadow API function. | |
* @param[in] pDocumentInfo Document info passed to Shadow API function. | |
* | |
* @return #AWS_IOT_SHADOW_SUCCESS or #AWS_IOT_SHADOW_BAD_PARAMETER. | |
*/ | |
static AwsIotShadowError_t _validateDocumentInfo( _shadowOperationType_t type, | |
uint32_t flags, | |
const AwsIotShadowDocumentInfo_t * pDocumentInfo ); | |
/** | |
* @brief Common function for setting Shadow callbacks. | |
* | |
* @param[in] mqttConnection The MQTT connection to use. | |
* @param[in] type Type of Shadow callback. | |
* @param[in] pThingName Thing Name for Shadow callback. | |
* @param[in] thingNameLength Length of `pThingName`. | |
* @param[in] pCallbackInfo Callback information to set. | |
* | |
* @return #AWS_IOT_SHADOW_SUCCESS, #AWS_IOT_SHADOW_BAD_PARAMETER, | |
* #AWS_IOT_SHADOW_NO_MEMORY, or #AWS_IOT_SHADOW_MQTT_ERROR. | |
*/ | |
static AwsIotShadowError_t _setCallbackCommon( IotMqttConnection_t mqttConnection, | |
_shadowCallbackType_t type, | |
const char * pThingName, | |
size_t thingNameLength, | |
const AwsIotShadowCallbackInfo_t * pCallbackInfo ); | |
/** | |
* @brief Change the subscriptions for Shadow callbacks, either by subscribing | |
* or unsubscribing. | |
* | |
* @param[in] mqttConnection The MQTT connection to use. | |
* @param[in] type Type of Shadow callback. | |
* @param[in] pSubscription Shadow subscriptions object for callback. | |
* @param[in] mqttOperation Either @ref mqtt_function_subscribesync or | |
* @ref mqtt_function_unsubscribesync. | |
* | |
* @return #AWS_IOT_SHADOW_SUCCESS, #AWS_IOT_SHADOW_NO_MEMORY, or | |
* #AWS_IOT_SHADOW_MQTT_ERROR. | |
*/ | |
static AwsIotShadowError_t _modifyCallbackSubscriptions( IotMqttConnection_t mqttConnection, | |
_shadowCallbackType_t type, | |
_shadowSubscription_t * pSubscription, | |
AwsIotMqttFunction_t mqttOperation ); | |
/** | |
* @brief Common function for incoming Shadow callbacks. | |
* | |
* @param[in] type Shadow callback type. | |
* @param[in] pMessage The received Shadow callback document (as an MQTT PUBLISH | |
* message). | |
*/ | |
static void _callbackWrapperCommon( _shadowCallbackType_t type, | |
IotMqttCallbackParam_t * pMessage ); | |
/** | |
* @brief Invoked when a document is received on the Shadow DELTA callback. | |
* | |
* @param[in] pArgument Ignored. | |
* @param[in] pMessage The received DELTA document (as an MQTT PUBLISH message). | |
*/ | |
static void _deltaCallbackWrapper( void * pArgument, | |
IotMqttCallbackParam_t * pMessage ); | |
/** | |
* @brief Invoked when a document is received on the Shadow UPDATED callback. | |
* | |
* @param[in] pArgument Ignored. | |
* @param[in] pMessage The received UPDATED document (as an MQTT PUBLISH message). | |
*/ | |
static void _updatedCallbackWrapper( void * pArgument, | |
IotMqttCallbackParam_t * pMessage ); | |
/*-----------------------------------------------------------*/ | |
/** | |
* @brief Tracks whether @ref shadow_function_init has been called. | |
* | |
* API functions will fail if @ref shadow_function_init was not called. | |
*/ | |
static uint32_t _initCalled = 0; | |
/** | |
* @brief Timeout used for MQTT operations. | |
*/ | |
uint32_t _AwsIotShadowMqttTimeoutMs = AWS_IOT_SHADOW_DEFAULT_MQTT_TIMEOUT_MS; | |
#if LIBRARY_LOG_LEVEL > IOT_LOG_NONE | |
/** | |
* @brief Printable names for the Shadow callbacks. | |
*/ | |
const char * const _pAwsIotShadowCallbackNames[] = | |
{ | |
"DELTA", | |
"UPDATED" | |
}; | |
#endif | |
/*-----------------------------------------------------------*/ | |
static bool _checkInit( void ) | |
{ | |
bool status = true; | |
if( _initCalled == 0 ) | |
{ | |
IotLogError( "AwsIotShadow_Init was not called." ); | |
status = false; | |
} | |
return status; | |
} | |
/*-----------------------------------------------------------*/ | |
static AwsIotShadowError_t _validateThingNameFlags( _shadowOperationType_t type, | |
const char * pThingName, | |
size_t thingNameLength, | |
uint32_t flags, | |
const AwsIotShadowCallbackInfo_t * pCallbackInfo, | |
const AwsIotShadowOperation_t * pOperation ) | |
{ | |
IOT_FUNCTION_ENTRY( AwsIotShadowError_t, AWS_IOT_SHADOW_SUCCESS ); | |
/* Type is not used when logging is disabled. */ | |
( void ) type; | |
/* Check Thing Name. */ | |
if( AwsIot_ValidateThingName( pThingName, thingNameLength ) == false ) | |
{ | |
IotLogError( "Thing Name for Shadow %s is not valid.", | |
_pAwsIotShadowOperationNames[ type ] ); | |
IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_PARAMETER ); | |
} | |
/* Check the waitable operation flag. */ | |
if( ( flags & AWS_IOT_SHADOW_FLAG_WAITABLE ) == AWS_IOT_SHADOW_FLAG_WAITABLE ) | |
{ | |
/* Check that a reference pointer is provided for a waitable operation. */ | |
if( pOperation == NULL ) | |
{ | |
IotLogError( "Reference must be set for a waitable Shadow %s.", | |
_pAwsIotShadowOperationNames[ type ] ); | |
IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_PARAMETER ); | |
} | |
/* A callback should not be set for a waitable operation. */ | |
if( pCallbackInfo != NULL ) | |
{ | |
IotLogError( "Callback should not be set for a waitable Shadow %s.", | |
_pAwsIotShadowOperationNames[ type ] ); | |
IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_PARAMETER ); | |
} | |
} | |
/* A callback info must be passed to a non-waitable GET. */ | |
if( ( type == SHADOW_GET ) && | |
( ( flags & AWS_IOT_SHADOW_FLAG_WAITABLE ) == 0 ) && | |
( pCallbackInfo == NULL ) ) | |
{ | |
IotLogError( "Callback info must be provided for non-waitable Shadow GET." ); | |
IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_PARAMETER ); | |
} | |
/* Check that a callback function is set. */ | |
if( ( pCallbackInfo != NULL ) && | |
( pCallbackInfo->function == NULL ) ) | |
{ | |
IotLogError( "Callback function must be set for Shadow %s callback.", | |
_pAwsIotShadowOperationNames[ type ] ); | |
IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_PARAMETER ); | |
} | |
IOT_FUNCTION_EXIT_NO_CLEANUP(); | |
} | |
/*-----------------------------------------------------------*/ | |
static AwsIotShadowError_t _validateDocumentInfo( _shadowOperationType_t type, | |
uint32_t flags, | |
const AwsIotShadowDocumentInfo_t * pDocumentInfo ) | |
{ | |
IOT_FUNCTION_ENTRY( AwsIotShadowError_t, AWS_IOT_SHADOW_SUCCESS ); | |
/* This function should only be called for Shadow GET or UPDATE. */ | |
AwsIotShadow_Assert( ( type == SHADOW_GET ) || ( type == SHADOW_UPDATE ) ); | |
/* Check QoS. */ | |
if( pDocumentInfo->qos != IOT_MQTT_QOS_0 ) | |
{ | |
if( pDocumentInfo->qos != IOT_MQTT_QOS_1 ) | |
{ | |
IotLogError( "QoS for Shadow %d must be 0 or 1.", | |
_pAwsIotShadowOperationNames[ type ] ); | |
IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_PARAMETER ); | |
} | |
} | |
/* Check the retry parameters. */ | |
if( pDocumentInfo->retryLimit > 0 ) | |
{ | |
if( pDocumentInfo->retryMs == 0 ) | |
{ | |
IotLogError( "Retry time of Shadow %s must be positive.", | |
_pAwsIotShadowOperationNames[ type ] ); | |
IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_PARAMETER ); | |
} | |
} | |
/* Check members relevant to a Shadow GET. */ | |
if( type == SHADOW_GET ) | |
{ | |
/* Check memory allocation function for waitable GET. */ | |
if( ( ( flags & AWS_IOT_SHADOW_FLAG_WAITABLE ) == AWS_IOT_SHADOW_FLAG_WAITABLE ) && | |
( pDocumentInfo->u.get.mallocDocument == NULL ) ) | |
{ | |
IotLogError( "Memory allocation function must be set for waitable Shadow GET." ); | |
IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_PARAMETER ); | |
} | |
} | |
/* Check members relevant to a Shadow UPDATE. */ | |
else | |
{ | |
/* Check UPDATE document pointer and length. */ | |
if( ( pDocumentInfo->u.update.pUpdateDocument == NULL ) || | |
( pDocumentInfo->u.update.updateDocumentLength == 0 ) ) | |
{ | |
IotLogError( "Shadow document for Shadow UPDATE cannot be NULL or" | |
" have length 0." ); | |
IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_PARAMETER ); | |
} | |
} | |
IOT_FUNCTION_EXIT_NO_CLEANUP(); | |
} | |
/*-----------------------------------------------------------*/ | |
static AwsIotShadowError_t _setCallbackCommon( IotMqttConnection_t mqttConnection, | |
_shadowCallbackType_t type, | |
const char * pThingName, | |
size_t thingNameLength, | |
const AwsIotShadowCallbackInfo_t * pCallbackInfo ) | |
{ | |
IOT_FUNCTION_ENTRY( AwsIotShadowError_t, AWS_IOT_SHADOW_SUCCESS ); | |
bool subscriptionMutexLocked = false; | |
_shadowSubscription_t * pSubscription = NULL; | |
/* Check that AwsIotShadow_Init was called. */ | |
if( _checkInit() == false ) | |
{ | |
IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_NOT_INITIALIZED ); | |
} | |
/* Check parameters. */ | |
status = _validateThingNameFlags( ( _shadowOperationType_t ) ( type + SHADOW_OPERATION_COUNT ), | |
pThingName, | |
thingNameLength, | |
0, | |
pCallbackInfo, | |
NULL ); | |
if( status != AWS_IOT_SHADOW_SUCCESS ) | |
{ | |
IOT_GOTO_CLEANUP(); | |
} | |
IotLogInfo( "(%.*s) Modifying Shadow %s callback.", | |
thingNameLength, | |
pThingName, | |
_pAwsIotShadowCallbackNames[ type ] ); | |
/* Lock the subscription list mutex to check for an existing subscription | |
* object. */ | |
IotMutex_Lock( &( _AwsIotShadowSubscriptionsMutex ) ); | |
subscriptionMutexLocked = true; | |
/* Check for an existing subscription. This function will attempt to allocate | |
* a new subscription if not found. */ | |
pSubscription = _AwsIotShadow_FindSubscription( pThingName, | |
thingNameLength, | |
true ); | |
if( pSubscription == NULL ) | |
{ | |
/* No existing subscription was found, and no new subscription could be | |
* allocated. */ | |
IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_NO_MEMORY ); | |
} | |
/* Check for an existing callback. */ | |
if( pSubscription->callbacks[ type ].function != NULL ) | |
{ | |
/* Replace existing callback. */ | |
if( pCallbackInfo != NULL ) | |
{ | |
IotLogInfo( "(%.*s) Found existing %s callback. Replacing callback.", | |
thingNameLength, | |
pThingName, | |
_pAwsIotShadowCallbackNames[ type ] ); | |
pSubscription->callbacks[ type ] = *pCallbackInfo; | |
} | |
/* Remove existing callback. */ | |
else | |
{ | |
IotLogInfo( "(%.*s) Removing existing %s callback.", | |
thingNameLength, | |
pThingName, | |
_pAwsIotShadowCallbackNames[ type ] ); | |
/* Unsubscribe, then clear the callback information. */ | |
( void ) _modifyCallbackSubscriptions( mqttConnection, | |
type, | |
pSubscription, | |
IotMqtt_UnsubscribeSync ); | |
( void ) memset( &( pSubscription->callbacks[ type ] ), | |
0x00, | |
sizeof( AwsIotShadowCallbackInfo_t ) ); | |
/* Check if this subscription object can be removed. */ | |
_AwsIotShadow_RemoveSubscription( pSubscription, NULL ); | |
} | |
} | |
/* No existing callback. */ | |
else | |
{ | |
/* Add new callback. */ | |
if( pCallbackInfo != NULL ) | |
{ | |
IotLogInfo( "(%.*s) Adding new %s callback.", | |
thingNameLength, | |
pThingName, | |
_pAwsIotShadowCallbackNames[ type ] ); | |
status = _modifyCallbackSubscriptions( mqttConnection, | |
type, | |
pSubscription, | |
IotMqtt_SubscribeSync ); | |
if( status == AWS_IOT_SHADOW_SUCCESS ) | |
{ | |
pSubscription->callbacks[ type ] = *pCallbackInfo; | |
} | |
else | |
{ | |
/* On failure, check if this subscription can be removed. */ | |
_AwsIotShadow_RemoveSubscription( pSubscription, NULL ); | |
} | |
} | |
/* Do nothing; set return value to success. */ | |
else | |
{ | |
status = AWS_IOT_SHADOW_SUCCESS; | |
} | |
} | |
IOT_FUNCTION_CLEANUP_BEGIN(); | |
if( subscriptionMutexLocked == true ) | |
{ | |
IotMutex_Unlock( &( _AwsIotShadowSubscriptionsMutex ) ); | |
} | |
IotLogInfo( "(%.*s) Shadow %s callback operation complete with result %s.", | |
thingNameLength, | |
pThingName, | |
_pAwsIotShadowCallbackNames[ type ], | |
AwsIotShadow_strerror( status ) ); | |
IOT_FUNCTION_CLEANUP_END(); | |
} | |
/*-----------------------------------------------------------*/ | |
static AwsIotShadowError_t _modifyCallbackSubscriptions( IotMqttConnection_t mqttConnection, | |
_shadowCallbackType_t type, | |
_shadowSubscription_t * pSubscription, | |
AwsIotMqttFunction_t mqttOperation ) | |
{ | |
IOT_FUNCTION_ENTRY( AwsIotShadowError_t, AWS_IOT_SHADOW_SUCCESS ); | |
IotMqttError_t mqttStatus = IOT_MQTT_STATUS_PENDING; | |
IotMqttSubscription_t subscription = IOT_MQTT_SUBSCRIPTION_INITIALIZER; | |
char * pTopicFilter = NULL; | |
uint16_t operationTopicLength = 0; | |
/* Lookup table for Shadow callback suffixes. */ | |
const char * const pCallbackSuffix[ SHADOW_CALLBACK_COUNT ] = | |
{ | |
SHADOW_DELTA_SUFFIX, /* Delta callback. */ | |
SHADOW_UPDATED_SUFFIX /* Updated callback. */ | |
}; | |
/* Lookup table for Shadow callback suffix lengths. */ | |
const uint16_t pCallbackSuffixLength[ SHADOW_CALLBACK_COUNT ] = | |
{ | |
SHADOW_DELTA_SUFFIX_LENGTH, /* Delta callback. */ | |
SHADOW_UPDATED_SUFFIX_LENGTH /* Updated callback. */ | |
}; | |
/* Lookup table for Shadow callback function wrappers. */ | |
const AwsIotMqttCallbackFunction_t pCallbackWrapper[ SHADOW_CALLBACK_COUNT ] = | |
{ | |
_deltaCallbackWrapper, /* Delta callback. */ | |
_updatedCallbackWrapper, /* Updated callback. */ | |
}; | |
/* MQTT operation may only be subscribe or unsubscribe. */ | |
AwsIotShadow_Assert( ( mqttOperation == IotMqtt_SubscribeSync ) || | |
( mqttOperation == IotMqtt_UnsubscribeSync ) ); | |
/* Use the subscription's topic buffer if available. */ | |
if( pSubscription->pTopicBuffer != NULL ) | |
{ | |
pTopicFilter = pSubscription->pTopicBuffer; | |
} | |
/* Generate the prefix portion of the Shadow callback topic filter. Both | |
* callbacks share the same callback as the Shadow Update operation. */ | |
status = _AwsIotShadow_GenerateShadowTopic( SHADOW_UPDATE, | |
pSubscription->pThingName, | |
pSubscription->thingNameLength, | |
&pTopicFilter, | |
&operationTopicLength ); | |
if( status != AWS_IOT_SHADOW_SUCCESS ) | |
{ | |
IOT_GOTO_CLEANUP(); | |
} | |
/* Place the callback suffix in the topic filter. */ | |
( void ) memcpy( pTopicFilter + operationTopicLength, | |
pCallbackSuffix[ type ], | |
pCallbackSuffixLength[ type ] ); | |
IotLogDebug( "%s subscription for %.*s", | |
mqttOperation == IotMqtt_SubscribeSync ? "Adding" : "Removing", | |
operationTopicLength + pCallbackSuffixLength[ type ], | |
pTopicFilter ); | |
/* Set the members of the MQTT subscription. */ | |
subscription.qos = IOT_MQTT_QOS_1; | |
subscription.pTopicFilter = pTopicFilter; | |
subscription.topicFilterLength = ( uint16_t ) ( operationTopicLength + pCallbackSuffixLength[ type ] ); | |
subscription.callback.pCallbackContext = NULL; | |
subscription.callback.function = pCallbackWrapper[ type ]; | |
/* Call the MQTT operation function. */ | |
mqttStatus = mqttOperation( mqttConnection, | |
&subscription, | |
1, | |
0, | |
_AwsIotShadowMqttTimeoutMs ); | |
/* Check the result of the MQTT operation. */ | |
if( mqttStatus != IOT_MQTT_SUCCESS ) | |
{ | |
IotLogError( "Failed to %s callback for %.*s %s callback, error %s.", | |
mqttOperation == IotMqtt_SubscribeSync ? "subscribe to" : "unsubscribe from", | |
pSubscription->thingNameLength, | |
pSubscription->pThingName, | |
_pAwsIotShadowCallbackNames[ type ], | |
IotMqtt_strerror( mqttStatus ) ); | |
/* Convert the MQTT "NO MEMORY" error to a Shadow "NO MEMORY" error. */ | |
IOT_SET_AND_GOTO_CLEANUP( SHADOW_CONVERT_STATUS_CODE_MQTT_TO_SHADOW( mqttStatus ) ); | |
} | |
IotLogDebug( "Successfully %s %.*s Shadow %s callback.", | |
mqttOperation == IotMqtt_SubscribeSync ? "subscribed to" : "unsubscribed from", | |
pSubscription->thingNameLength, | |
pSubscription->pThingName, | |
_pAwsIotShadowCallbackNames[ type ] ); | |
IOT_FUNCTION_CLEANUP_BEGIN(); | |
/* MQTT subscribe should check the subscription topic buffer. */ | |
if( mqttOperation == IotMqtt_SubscribeSync ) | |
{ | |
/* If the current subscription has no topic buffer, assign it the current | |
* topic buffer. */ | |
if( pSubscription->pTopicBuffer == NULL ) | |
{ | |
pSubscription->pTopicBuffer = pTopicFilter; | |
} | |
} | |
IOT_FUNCTION_CLEANUP_END(); | |
} | |
/*-----------------------------------------------------------*/ | |
static void _callbackWrapperCommon( _shadowCallbackType_t type, | |
IotMqttCallbackParam_t * pMessage ) | |
{ | |
AwsIotShadowCallbackInfo_t callbackInfo = AWS_IOT_SHADOW_CALLBACK_INFO_INITIALIZER; | |
AwsIotShadowCallbackParam_t callbackParam = { .callbackType = ( AwsIotShadowCallbackType_t ) 0 }; | |
_shadowSubscription_t * pSubscription = NULL; | |
const char * pThingName = NULL; | |
size_t thingNameLength = 0; | |
/* Parse the Thing Name from the topic. */ | |
if( AwsIot_ParseThingName( pMessage->u.message.info.pTopicName, | |
pMessage->u.message.info.topicNameLength, | |
&pThingName, | |
&thingNameLength ) == false ) | |
{ | |
IOT_GOTO_CLEANUP(); | |
} | |
/* Search for a matching subscription. */ | |
IotMutex_Lock( &_AwsIotShadowSubscriptionsMutex ); | |
pSubscription = _AwsIotShadow_FindSubscription( pThingName, | |
thingNameLength, | |
false ); | |
if( pSubscription == NULL ) | |
{ | |
/* No subscription found. */ | |
IotMutex_Unlock( &_AwsIotShadowSubscriptionsMutex ); | |
IOT_GOTO_CLEANUP(); | |
} | |
/* Ensure that a callback function is set. */ | |
AwsIotShadow_Assert( pSubscription->callbacks[ type ].function != NULL ); | |
/* Copy the subscription callback info, as the subscription may be modified | |
* when the subscriptions mutex is released. */ | |
callbackInfo = pSubscription->callbacks[ type ]; | |
IotMutex_Unlock( &_AwsIotShadowSubscriptionsMutex ); | |
/* Set the callback type. Shadow callbacks are enumerated after the operations. */ | |
callbackParam.callbackType = ( AwsIotShadowCallbackType_t ) ( type + SHADOW_OPERATION_COUNT ); | |
/* Set the remaining members of the callback param. */ | |
callbackParam.mqttConnection = pMessage->mqttConnection; | |
callbackParam.pThingName = pThingName; | |
callbackParam.thingNameLength = thingNameLength; | |
callbackParam.u.callback.pDocument = pMessage->u.message.info.pPayload; | |
callbackParam.u.callback.documentLength = pMessage->u.message.info.payloadLength; | |
/* Invoke the callback function. */ | |
callbackInfo.function( callbackInfo.pCallbackContext, | |
&callbackParam ); | |
/* This function uses cleanup sections to exit on error. */ | |
IOT_FUNCTION_CLEANUP_BEGIN(); | |
} | |
/*-----------------------------------------------------------*/ | |
static void _deltaCallbackWrapper( void * pArgument, | |
IotMqttCallbackParam_t * pMessage ) | |
{ | |
/* Silence warnings about unused parameters. */ | |
( void ) pArgument; | |
_callbackWrapperCommon( DELTA_CALLBACK, pMessage ); | |
} | |
/*-----------------------------------------------------------*/ | |
static void _updatedCallbackWrapper( void * pArgument, | |
IotMqttCallbackParam_t * pMessage ) | |
{ | |
/* Silence warnings about unused parameters. */ | |
( void ) pArgument; | |
_callbackWrapperCommon( UPDATED_CALLBACK, pMessage ); | |
} | |
/*-----------------------------------------------------------*/ | |
AwsIotShadowError_t AwsIotShadow_Init( uint32_t mqttTimeoutMs ) | |
{ | |
AwsIotShadowError_t status = AWS_IOT_SHADOW_SUCCESS; | |
bool listInitStatus = false; | |
if( _initCalled == 0 ) | |
{ | |
/* Initialize Shadow lists and mutexes. */ | |
listInitStatus = AwsIot_InitLists( &_AwsIotShadowPendingOperations, | |
&_AwsIotShadowSubscriptions, | |
&_AwsIotShadowPendingOperationsMutex, | |
&_AwsIotShadowSubscriptionsMutex ); | |
if( listInitStatus == false ) | |
{ | |
IotLogInfo( "Failed to create Shadow lists." ); | |
status = AWS_IOT_SHADOW_INIT_FAILED; | |
} | |
else | |
{ | |
/* Save the MQTT timeout option. */ | |
if( mqttTimeoutMs != 0 ) | |
{ | |
_AwsIotShadowMqttTimeoutMs = mqttTimeoutMs; | |
} | |
/* Set the flag that specifies initialization is complete. */ | |
_initCalled = 1; | |
IotLogInfo( "Shadow library successfully initialized." ); | |
} | |
} | |
else | |
{ | |
IotLogWarn( "AwsIotShadow_Init called with library already initialized." ); | |
} | |
return status; | |
} | |
/*-----------------------------------------------------------*/ | |
void AwsIotShadow_Cleanup( void ) | |
{ | |
if( _initCalled == 1 ) | |
{ | |
_initCalled = 0; | |
/* Remove and free all items in the Shadow pending operation list. */ | |
IotMutex_Lock( &( _AwsIotShadowPendingOperationsMutex ) ); | |
IotListDouble_RemoveAll( &( _AwsIotShadowPendingOperations ), | |
_AwsIotShadow_DestroyOperation, | |
offsetof( _shadowOperation_t, link ) ); | |
IotMutex_Unlock( &( _AwsIotShadowPendingOperationsMutex ) ); | |
/* Remove and free all items in the Shadow subscription list. */ | |
IotMutex_Lock( &( _AwsIotShadowSubscriptionsMutex ) ); | |
IotListDouble_RemoveAll( &( _AwsIotShadowSubscriptions ), | |
_AwsIotShadow_DestroySubscription, | |
offsetof( _shadowSubscription_t, link ) ); | |
IotMutex_Unlock( &( _AwsIotShadowSubscriptionsMutex ) ); | |
/* Destroy Shadow library mutexes. */ | |
IotMutex_Destroy( &( _AwsIotShadowPendingOperationsMutex ) ); | |
IotMutex_Destroy( &( _AwsIotShadowSubscriptionsMutex ) ); | |
/* Restore the default MQTT timeout. */ | |
_AwsIotShadowMqttTimeoutMs = AWS_IOT_SHADOW_DEFAULT_MQTT_TIMEOUT_MS; | |
IotLogInfo( "Shadow library cleanup done." ); | |
} | |
else | |
{ | |
IotLogWarn( "AwsIotShadow_Init was not called before AwsIotShadow_Cleanup." ); | |
} | |
} | |
/*-----------------------------------------------------------*/ | |
AwsIotShadowError_t AwsIotShadow_DeleteAsync( IotMqttConnection_t mqttConnection, | |
const char * pThingName, | |
size_t thingNameLength, | |
uint32_t flags, | |
const AwsIotShadowCallbackInfo_t * pCallbackInfo, | |
AwsIotShadowOperation_t * const pDeleteOperation ) | |
{ | |
IOT_FUNCTION_ENTRY( AwsIotShadowError_t, AWS_IOT_SHADOW_STATUS_PENDING ); | |
_shadowOperation_t * pOperation = NULL; | |
/* Check that AwsIotShadow_Init was called. */ | |
if( _checkInit() == false ) | |
{ | |
IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_NOT_INITIALIZED ); | |
} | |
/* Validate the Thing Name and flags for Shadow DELETE. */ | |
status = _validateThingNameFlags( SHADOW_DELETE, | |
pThingName, | |
thingNameLength, | |
flags, | |
pCallbackInfo, | |
pDeleteOperation ); | |
if( status != AWS_IOT_SHADOW_SUCCESS ) | |
{ | |
/* The Thing Name or some flag was invalid. */ | |
IOT_GOTO_CLEANUP(); | |
} | |
/* Allocate a new Shadow operation for DELETE. */ | |
status = _AwsIotShadow_CreateOperation( &pOperation, | |
SHADOW_DELETE, | |
flags, | |
pCallbackInfo ); | |
if( status != AWS_IOT_SHADOW_SUCCESS ) | |
{ | |
/* No memory for a new Shadow operation. */ | |
IOT_GOTO_CLEANUP(); | |
} | |
/* Check the members set by Shadow operation creation. */ | |
AwsIotShadow_Assert( pOperation != NULL ); | |
AwsIotShadow_Assert( pOperation->type == SHADOW_DELETE ); | |
AwsIotShadow_Assert( pOperation->flags == flags ); | |
AwsIotShadow_Assert( pOperation->status == AWS_IOT_SHADOW_STATUS_PENDING ); | |
/* Set the reference if provided. This must be done before the Shadow operation | |
* is processed. */ | |
if( pDeleteOperation != NULL ) | |
{ | |
*pDeleteOperation = pOperation; | |
} | |
/* Process the Shadow operation. This subscribes to any required topics and | |
* sends the MQTT message for the Shadow operation. */ | |
status = _AwsIotShadow_ProcessOperation( mqttConnection, | |
pThingName, | |
thingNameLength, | |
pOperation, | |
NULL ); | |
/* If the Shadow operation failed, clear the now invalid reference. */ | |
if( ( status != AWS_IOT_SHADOW_STATUS_PENDING ) && ( pDeleteOperation != NULL ) ) | |
{ | |
*pDeleteOperation = AWS_IOT_SHADOW_OPERATION_INITIALIZER; | |
} | |
IOT_FUNCTION_EXIT_NO_CLEANUP(); | |
} | |
/*-----------------------------------------------------------*/ | |
AwsIotShadowError_t AwsIotShadow_DeleteSync( IotMqttConnection_t mqttConnection, | |
const char * pThingName, | |
size_t thingNameLength, | |
uint32_t flags, | |
uint32_t timeoutMs ) | |
{ | |
AwsIotShadowError_t status = AWS_IOT_SHADOW_STATUS_PENDING; | |
AwsIotShadowOperation_t deleteOperation = AWS_IOT_SHADOW_OPERATION_INITIALIZER; | |
/* Set the waitable flag. */ | |
flags |= AWS_IOT_SHADOW_FLAG_WAITABLE; | |
/* Call the asynchronous Shadow delete function. */ | |
status = AwsIotShadow_DeleteAsync( mqttConnection, | |
pThingName, | |
thingNameLength, | |
flags, | |
NULL, | |
&deleteOperation ); | |
/* Wait for the Shadow delete operation to complete. */ | |
if( status == AWS_IOT_SHADOW_STATUS_PENDING ) | |
{ | |
status = AwsIotShadow_Wait( deleteOperation, timeoutMs, NULL, NULL ); | |
} | |
/* Ensure that a status was set. */ | |
AwsIotShadow_Assert( status != AWS_IOT_SHADOW_STATUS_PENDING ); | |
return status; | |
} | |
/*-----------------------------------------------------------*/ | |
AwsIotShadowError_t AwsIotShadow_GetAsync( IotMqttConnection_t mqttConnection, | |
const AwsIotShadowDocumentInfo_t * pGetInfo, | |
uint32_t flags, | |
const AwsIotShadowCallbackInfo_t * pCallbackInfo, | |
AwsIotShadowOperation_t * const pGetOperation ) | |
{ | |
IOT_FUNCTION_ENTRY( AwsIotShadowError_t, AWS_IOT_SHADOW_STATUS_PENDING ); | |
_shadowOperation_t * pOperation = NULL; | |
/* Check that AwsIotShadow_Init was called. */ | |
if( _checkInit() == false ) | |
{ | |
IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_NOT_INITIALIZED ); | |
} | |
/* Validate the Thing Name and flags for Shadow GET. */ | |
status = _validateThingNameFlags( SHADOW_GET, | |
pGetInfo->pThingName, | |
pGetInfo->thingNameLength, | |
flags, | |
pCallbackInfo, | |
pGetOperation ); | |
if( status != AWS_IOT_SHADOW_SUCCESS ) | |
{ | |
/* The Thing Name or some flag was invalid. */ | |
IOT_GOTO_CLEANUP(); | |
} | |
/* Validate the document info for Shadow GET. */ | |
status = _validateDocumentInfo( SHADOW_GET, | |
flags, | |
pGetInfo ); | |
if( status != AWS_IOT_SHADOW_SUCCESS ) | |
{ | |
/* Document info was invalid. */ | |
IOT_GOTO_CLEANUP(); | |
} | |
/* Allocate a new Shadow operation for GET. */ | |
status = _AwsIotShadow_CreateOperation( &pOperation, | |
SHADOW_GET, | |
flags, | |
pCallbackInfo ); | |
if( status != AWS_IOT_SHADOW_SUCCESS ) | |
{ | |
/* No memory for a new Shadow operation. */ | |
IOT_GOTO_CLEANUP(); | |
} | |
/* Check the members set by Shadow operation creation. */ | |
AwsIotShadow_Assert( pOperation != NULL ); | |
AwsIotShadow_Assert( pOperation->type == SHADOW_GET ); | |
AwsIotShadow_Assert( pOperation->flags == flags ); | |
AwsIotShadow_Assert( pOperation->status == AWS_IOT_SHADOW_STATUS_PENDING ); | |
/* Copy the memory allocation function. */ | |
pOperation->u.get.mallocDocument = pGetInfo->u.get.mallocDocument; | |
/* Set the reference if provided. This must be done before the Shadow operation | |
* is processed. */ | |
if( pGetOperation != NULL ) | |
{ | |
*pGetOperation = pOperation; | |
} | |
/* Process the Shadow operation. This subscribes to any required topics and | |
* sends the MQTT message for the Shadow operation. */ | |
status = _AwsIotShadow_ProcessOperation( mqttConnection, | |
pGetInfo->pThingName, | |
pGetInfo->thingNameLength, | |
pOperation, | |
pGetInfo ); | |
/* If the Shadow operation failed, clear the now invalid reference. */ | |
if( ( status != AWS_IOT_SHADOW_STATUS_PENDING ) && ( pGetOperation != NULL ) ) | |
{ | |
*pGetOperation = AWS_IOT_SHADOW_OPERATION_INITIALIZER; | |
} | |
IOT_FUNCTION_EXIT_NO_CLEANUP(); | |
} | |
/*-----------------------------------------------------------*/ | |
AwsIotShadowError_t AwsIotShadow_GetSync( IotMqttConnection_t mqttConnection, | |
const AwsIotShadowDocumentInfo_t * pGetInfo, | |
uint32_t flags, | |
uint32_t timeoutMs, | |
const char ** const pShadowDocument, | |
size_t * const pShadowDocumentLength ) | |
{ | |
AwsIotShadowError_t status = AWS_IOT_SHADOW_STATUS_PENDING; | |
AwsIotShadowOperation_t getOperation = AWS_IOT_SHADOW_OPERATION_INITIALIZER; | |
/* Set the waitable flag. */ | |
flags |= AWS_IOT_SHADOW_FLAG_WAITABLE; | |
/* Call the asynchronous Shadow get function. */ | |
status = AwsIotShadow_GetAsync( mqttConnection, | |
pGetInfo, | |
flags, | |
NULL, | |
&getOperation ); | |
/* Wait for the Shadow get operation to complete. */ | |
if( status == AWS_IOT_SHADOW_STATUS_PENDING ) | |
{ | |
status = AwsIotShadow_Wait( getOperation, | |
timeoutMs, | |
pShadowDocument, | |
pShadowDocumentLength ); | |
} | |
/* Ensure that a status was set. */ | |
AwsIotShadow_Assert( status != AWS_IOT_SHADOW_STATUS_PENDING ); | |
return status; | |
} | |
/*-----------------------------------------------------------*/ | |
AwsIotShadowError_t AwsIotShadow_UpdateAsync( IotMqttConnection_t mqttConnection, | |
const AwsIotShadowDocumentInfo_t * pUpdateInfo, | |
uint32_t flags, | |
const AwsIotShadowCallbackInfo_t * pCallbackInfo, | |
AwsIotShadowOperation_t * const pUpdateOperation ) | |
{ | |
IOT_FUNCTION_ENTRY( AwsIotShadowError_t, AWS_IOT_SHADOW_STATUS_PENDING ); | |
_shadowOperation_t * pOperation = NULL; | |
const char * pClientToken = NULL; | |
size_t clientTokenLength = 0; | |
/* Check that AwsIotShadow_Init was called. */ | |
if( _checkInit() == false ) | |
{ | |
IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_NOT_INITIALIZED ); | |
} | |
/* Validate the Thing Name and flags for Shadow UPDATE. */ | |
status = _validateThingNameFlags( SHADOW_UPDATE, | |
pUpdateInfo->pThingName, | |
pUpdateInfo->thingNameLength, | |
flags, | |
pCallbackInfo, | |
pUpdateOperation ); | |
if( status != AWS_IOT_SHADOW_SUCCESS ) | |
{ | |
/* The Thing Name or some flag was invalid. */ | |
IOT_GOTO_CLEANUP(); | |
} | |
/* Validate the document info for Shadow UPDATE. */ | |
status = _validateDocumentInfo( SHADOW_UPDATE, | |
flags, | |
pUpdateInfo ); | |
if( status != AWS_IOT_SHADOW_SUCCESS ) | |
{ | |
/* Document info was invalid. */ | |
IOT_GOTO_CLEANUP(); | |
} | |
/* Check UPDATE document for a client token. */ | |
if( AwsIot_GetClientToken( pUpdateInfo->u.update.pUpdateDocument, | |
pUpdateInfo->u.update.updateDocumentLength, | |
&pClientToken, | |
&clientTokenLength ) == false ) | |
{ | |
IotLogError( "Shadow document for Shadow UPDATE does not contain a valid client token." ); | |
IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_PARAMETER ); | |
} | |
/* Allocate a new Shadow operation for UPDATE. */ | |
status = _AwsIotShadow_CreateOperation( &pOperation, | |
SHADOW_UPDATE, | |
flags, | |
pCallbackInfo ); | |
if( status != AWS_IOT_SHADOW_SUCCESS ) | |
{ | |
/* No memory for a new Shadow operation. */ | |
IOT_GOTO_CLEANUP(); | |
} | |
/* Check the members set by Shadow operation creation. */ | |
AwsIotShadow_Assert( pOperation != NULL ); | |
AwsIotShadow_Assert( pOperation->type == SHADOW_UPDATE ); | |
AwsIotShadow_Assert( pOperation->flags == flags ); | |
AwsIotShadow_Assert( pOperation->status == AWS_IOT_SHADOW_STATUS_PENDING ); | |
/* Allocate memory for the client token. */ | |
pOperation->u.update.pClientToken = AwsIotShadow_MallocString( clientTokenLength ); | |
if( pOperation->u.update.pClientToken == NULL ) | |
{ | |
IotLogError( "Failed to allocate memory for Shadow update client token." ); | |
_AwsIotShadow_DestroyOperation( pOperation ); | |
IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_NO_MEMORY ); | |
} | |
/* Copy the client token. The client token must be copied in case the application | |
* frees the buffer containing it. */ | |
( void ) memcpy( ( void * ) pOperation->u.update.pClientToken, | |
pClientToken, | |
clientTokenLength ); | |
pOperation->u.update.clientTokenLength = clientTokenLength; | |
/* Set the reference if provided. This must be done before the Shadow operation | |
* is processed. */ | |
if( pUpdateOperation != NULL ) | |
{ | |
*pUpdateOperation = pOperation; | |
} | |
/* Process the Shadow operation. This subscribes to any required topics and | |
* sends the MQTT message for the Shadow operation. */ | |
status = _AwsIotShadow_ProcessOperation( mqttConnection, | |
pUpdateInfo->pThingName, | |
pUpdateInfo->thingNameLength, | |
pOperation, | |
pUpdateInfo ); | |
/* If the Shadow operation failed, clear the now invalid reference. */ | |
if( ( status != AWS_IOT_SHADOW_STATUS_PENDING ) && ( pUpdateOperation != NULL ) ) | |
{ | |
*pUpdateOperation = AWS_IOT_SHADOW_OPERATION_INITIALIZER; | |
} | |
IOT_FUNCTION_EXIT_NO_CLEANUP(); | |
} | |
/*-----------------------------------------------------------*/ | |
AwsIotShadowError_t AwsIotShadow_UpdateSync( IotMqttConnection_t mqttConnection, | |
const AwsIotShadowDocumentInfo_t * pUpdateInfo, | |
uint32_t flags, | |
uint32_t timeoutMs ) | |
{ | |
AwsIotShadowError_t status = AWS_IOT_SHADOW_STATUS_PENDING; | |
AwsIotShadowOperation_t updateOperation = AWS_IOT_SHADOW_OPERATION_INITIALIZER; | |
/* Set the waitable flag. */ | |
flags |= AWS_IOT_SHADOW_FLAG_WAITABLE; | |
/* Call the asynchronous Shadow update function. */ | |
status = AwsIotShadow_UpdateAsync( mqttConnection, | |
pUpdateInfo, | |
flags, | |
NULL, | |
&updateOperation ); | |
/* Wait for the Shadow update operation to complete. */ | |
if( status == AWS_IOT_SHADOW_STATUS_PENDING ) | |
{ | |
status = AwsIotShadow_Wait( updateOperation, timeoutMs, NULL, NULL ); | |
} | |
/* Ensure that a status was set. */ | |
AwsIotShadow_Assert( status != AWS_IOT_SHADOW_STATUS_PENDING ); | |
return status; | |
} | |
/*-----------------------------------------------------------*/ | |
AwsIotShadowError_t AwsIotShadow_Wait( AwsIotShadowOperation_t operation, | |
uint32_t timeoutMs, | |
const char ** const pShadowDocument, | |
size_t * const pShadowDocumentLength ) | |
{ | |
IOT_FUNCTION_ENTRY( AwsIotShadowError_t, AWS_IOT_SHADOW_STATUS_PENDING ); | |
/* Check that AwsIotShadow_Init was called. */ | |
if( _checkInit() == false ) | |
{ | |
IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_NOT_INITIALIZED ); | |
} | |
/* Check that reference is set. */ | |
if( operation == NULL ) | |
{ | |
IotLogError( "Operation reference cannot be NULL." ); | |
IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_PARAMETER ); | |
} | |
/* Check that reference is waitable. */ | |
if( ( operation->flags & AWS_IOT_SHADOW_FLAG_WAITABLE ) == 0 ) | |
{ | |
IotLogError( "Operation is not waitable." ); | |
IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_PARAMETER ); | |
} | |
/* Check that output parameters are set for a Shadow GET. */ | |
if( operation->type == SHADOW_GET ) | |
{ | |
if( ( pShadowDocument == NULL ) || ( pShadowDocumentLength == NULL ) ) | |
{ | |
IotLogError( "Output buffer and size pointer must be set for Shadow GET." ); | |
IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_PARAMETER ); | |
} | |
} | |
/* Wait for a response to the Shadow operation. */ | |
if( IotSemaphore_TimedWait( &( operation->notify.waitSemaphore ), | |
timeoutMs ) == true ) | |
{ | |
status = operation->status; | |
} | |
else | |
{ | |
status = AWS_IOT_SHADOW_TIMEOUT; | |
} | |
/* Remove the completed operation from the pending operation list. */ | |
IotMutex_Lock( &( _AwsIotShadowPendingOperationsMutex ) ); | |
IotListDouble_Remove( &( operation->link ) ); | |
IotMutex_Unlock( &( _AwsIotShadowPendingOperationsMutex ) ); | |
/* Decrement the reference count. This also removes subscriptions if the | |
* count reaches 0. */ | |
IotMutex_Lock( &_AwsIotShadowSubscriptionsMutex ); | |
_AwsIotShadow_DecrementReferences( operation, | |
operation->pSubscription->pTopicBuffer, | |
NULL ); | |
IotMutex_Unlock( &_AwsIotShadowSubscriptionsMutex ); | |
/* Set the output parameters for Shadow GET. */ | |
if( ( operation->type == SHADOW_GET ) && | |
( status == AWS_IOT_SHADOW_SUCCESS ) ) | |
{ | |
*pShadowDocument = operation->u.get.pDocument; | |
*pShadowDocumentLength = operation->u.get.documentLength; | |
} | |
/* Destroy the Shadow operation. */ | |
_AwsIotShadow_DestroyOperation( operation ); | |
IOT_FUNCTION_EXIT_NO_CLEANUP(); | |
} | |
/*-----------------------------------------------------------*/ | |
AwsIotShadowError_t AwsIotShadow_SetDeltaCallback( IotMqttConnection_t mqttConnection, | |
const char * pThingName, | |
size_t thingNameLength, | |
uint32_t flags, | |
const AwsIotShadowCallbackInfo_t * pDeltaCallback ) | |
{ | |
/* Flags are currently not used by this function. */ | |
( void ) flags; | |
return _setCallbackCommon( mqttConnection, | |
DELTA_CALLBACK, | |
pThingName, | |
thingNameLength, | |
pDeltaCallback ); | |
} | |
/*-----------------------------------------------------------*/ | |
AwsIotShadowError_t AwsIotShadow_SetUpdatedCallback( IotMqttConnection_t mqttConnection, | |
const char * pThingName, | |
size_t thingNameLength, | |
uint32_t flags, | |
const AwsIotShadowCallbackInfo_t * pUpdatedCallback ) | |
{ | |
/* Flags are currently not used by this function. */ | |
( void ) flags; | |
return _setCallbackCommon( mqttConnection, | |
UPDATED_CALLBACK, | |
pThingName, | |
thingNameLength, | |
pUpdatedCallback ); | |
} | |
/*-----------------------------------------------------------*/ | |
const char * AwsIotShadow_strerror( AwsIotShadowError_t status ) | |
{ | |
const char * pMessage = NULL; | |
switch( status ) | |
{ | |
case AWS_IOT_SHADOW_SUCCESS: | |
pMessage = "SUCCESS"; | |
break; | |
case AWS_IOT_SHADOW_STATUS_PENDING: | |
pMessage = "STATUS PENDING"; | |
break; | |
case AWS_IOT_SHADOW_INIT_FAILED: | |
pMessage = "INITIALIZATION FAILED"; | |
break; | |
case AWS_IOT_SHADOW_BAD_PARAMETER: | |
pMessage = "BAD PARAMETER"; | |
break; | |
case AWS_IOT_SHADOW_NO_MEMORY: | |
pMessage = "NO MEMORY"; | |
break; | |
case AWS_IOT_SHADOW_MQTT_ERROR: | |
pMessage = "MQTT LIBRARY ERROR"; | |
break; | |
case AWS_IOT_SHADOW_BAD_RESPONSE: | |
pMessage = "BAD RESPONSE RECEIVED"; | |
break; | |
case AWS_IOT_SHADOW_TIMEOUT: | |
pMessage = "TIMEOUT"; | |
break; | |
case AWS_IOT_SHADOW_NOT_INITIALIZED: | |
pMessage = "NOT INITIALIZED"; | |
break; | |
case AWS_IOT_SHADOW_BAD_REQUEST: | |
pMessage = "REJECTED: 400 BAD REQUEST"; | |
break; | |
case AWS_IOT_SHADOW_UNAUTHORIZED: | |
pMessage = "REJECTED: 401 UNAUTHORIZED"; | |
break; | |
case AWS_IOT_SHADOW_FORBIDDEN: | |
pMessage = "REJECTED: 403 FORBIDDEN"; | |
break; | |
case AWS_IOT_SHADOW_NOT_FOUND: | |
pMessage = "REJECTED: 404 NOT FOUND"; | |
break; | |
case AWS_IOT_SHADOW_CONFLICT: | |
pMessage = "REJECTED: 409 VERSION CONFLICT"; | |
break; | |
case AWS_IOT_SHADOW_TOO_LARGE: | |
pMessage = "REJECTED: 413 PAYLOAD TOO LARGE"; | |
break; | |
case AWS_IOT_SHADOW_UNSUPPORTED: | |
pMessage = "REJECTED: 415 UNSUPPORTED ENCODING"; | |
break; | |
case AWS_IOT_SHADOW_TOO_MANY_REQUESTS: | |
pMessage = "REJECTED: 429 TOO MANY REQUESTS"; | |
break; | |
case AWS_IOT_SHADOW_SERVER_ERROR: | |
pMessage = "500 SERVER ERROR"; | |
break; | |
default: | |
pMessage = "INVALID STATUS"; | |
break; | |
} | |
return pMessage; | |
} | |
/*-----------------------------------------------------------*/ |