Demo application for using the AT&T IoT Starter Kit Powered by AWS.
Dependencies: SDFileSystem
Fork of ATT_AWS_IoT_demo by
IoT Starter Kit Powered by AWS Demo
This program demonstrates the AT&T IoT Starter Kit sending data directly into AWS IoT. It's explained and used in the Getting Started with the IoT Starter Kit Powered by AWS on starterkit.att.com.
What's required
- AT&T IoT LTE Add-on (also known as the Cellular Shield)
- NXP K64F - for programming
- microSD card - used to store your AWS security credentials
- AWS account
- Python, locally installed
If you don't already have an IoT Starter Kit, you can purchase a kit here. The IoT Starter Kit Powered by AWS includes the LTE cellular shield, K64F, and a microSD card.
Diff: AWS_openssl/aws_iot_src/shadow/aws_iot_shadow_json.cpp
- Revision:
- 15:6f2798e45099
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AWS_openssl/aws_iot_src/shadow/aws_iot_shadow_json.cpp Thu Dec 01 18:05:38 2016 +0000 @@ -0,0 +1,461 @@ +/* + * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include "aws_iot_shadow_json.h" + +#include <string.h> +#include <stdbool.h> +#include <inttypes.h> +#include "aws_iot_json_utils.h" +#include "aws_iot_log.h" +#include "aws_iot_shadow_key.h" +#include "aws_iot_config.h" + +extern char mqttClientID[MAX_SIZE_OF_UNIQUE_CLIENT_ID_BYTES]; + +static uint32_t clientTokenNum = 0; + +//helper functions +static IoT_Error_t convertDataToString(char *pStringBuffer, size_t maxSizoStringBuffer, JsonPrimitiveType type, + void *pData); + +void resetClientTokenSequenceNum(void) { + clientTokenNum = 0; +} + +static void emptyJsonWithClientToken(char *pJsonDocument) { + sprintf(pJsonDocument, "{\"clientToken\":\""); + FillWithClientToken(pJsonDocument + strlen(pJsonDocument)); + sprintf(pJsonDocument + strlen(pJsonDocument), "\"}"); +} + +void iot_shadow_get_request_json(char *pJsonDocument) { + emptyJsonWithClientToken(pJsonDocument); +} + +void iot_shadow_delete_request_json(char *pJsonDocument) { + emptyJsonWithClientToken(pJsonDocument); +} + +static inline IoT_Error_t checkReturnValueOfSnPrintf(int32_t snPrintfReturn, size_t maxSizeOfJsonDocument) { + + if (snPrintfReturn >= maxSizeOfJsonDocument) { + return SHADOW_JSON_BUFFER_TRUNCATED; + } else if (snPrintfReturn < 0) { + return SHADOW_JSON_ERROR; + } + return NONE_ERROR; +} + +IoT_Error_t aws_iot_shadow_init_json_document(char *pJsonDocument, size_t maxSizeOfJsonDocument) { + + IoT_Error_t ret_val = NONE_ERROR; + int32_t snPrintfReturn = 0; + + if (pJsonDocument == NULL) { + return NULL_VALUE_ERROR; + } + snPrintfReturn = snprintf(pJsonDocument, maxSizeOfJsonDocument, "{\"state\":{"); + + ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, maxSizeOfJsonDocument); + + return ret_val; + +} + +IoT_Error_t aws_iot_shadow_add_desired(char *pJsonDocument, size_t maxSizeOfJsonDocument, uint8_t count, ...) { + IoT_Error_t ret_val = NONE_ERROR; + int32_t tempSize = 0; + int8_t i; + size_t remSizeOfJsonBuffer = maxSizeOfJsonDocument; + int32_t snPrintfReturn = 0; + va_list pArgs; + va_start(pArgs, count); + jsonStruct_t *pTemporary; + + if (pJsonDocument == NULL) { + return NULL_VALUE_ERROR; + } + + tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument); + if(tempSize <= 1){ + return SHADOW_JSON_ERROR; + } + remSizeOfJsonBuffer = tempSize; + + snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer, "\"desired\":{"); + ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer); + + if (ret_val != NONE_ERROR) { + return ret_val; + } + + for (i = 0; i < count; i++) { + tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument); + if(tempSize <= 1){ + return SHADOW_JSON_ERROR; + } + remSizeOfJsonBuffer = tempSize; + pTemporary = va_arg (pArgs, jsonStruct_t *); + if (pTemporary != NULL) { + snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer, "\"%s\":", + pTemporary->pKey); + ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer); + if (ret_val != NONE_ERROR) { + return ret_val; + } + if (pTemporary->pKey != NULL && pTemporary->pData != NULL) { + ret_val = convertDataToString(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer, + pTemporary->type, pTemporary->pData); + } else { + return NULL_VALUE_ERROR; + } + if (ret_val != NONE_ERROR) { + return ret_val; + } + } else { + return NULL_VALUE_ERROR; + } + } + + va_end(pArgs); + snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument) - 1, remSizeOfJsonBuffer, "},"); + ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer); + return ret_val; +} + +IoT_Error_t aws_iot_shadow_add_reported(char *pJsonDocument, size_t maxSizeOfJsonDocument, uint8_t count, ...) { + IoT_Error_t ret_val = NONE_ERROR; + + int8_t i; + size_t remSizeOfJsonBuffer = maxSizeOfJsonDocument; + int32_t snPrintfReturn = 0; + int32_t tempSize = 0; + va_list pArgs; + va_start(pArgs, count); + jsonStruct_t *pTemporary; + + if (pJsonDocument == NULL) { + return NULL_VALUE_ERROR; + } + + + tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument); + if(tempSize <= 1){ + return SHADOW_JSON_ERROR; + } + remSizeOfJsonBuffer = tempSize; + + snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer, "\"reported\":{"); + ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer); + + if (ret_val != NONE_ERROR) { + return ret_val; + } + + for (i = 0; i < count; i++) { + tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument); + if(tempSize <= 1){ + return SHADOW_JSON_ERROR; + } + remSizeOfJsonBuffer = tempSize; + + pTemporary = va_arg (pArgs, jsonStruct_t *); + if (pTemporary != NULL) { + snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer, "\"%s\":", + pTemporary->pKey); + ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer); + if (ret_val != NONE_ERROR) { + return ret_val; + } + if (pTemporary->pKey != NULL && pTemporary->pData != NULL) { + ret_val = convertDataToString(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer, + pTemporary->type, pTemporary->pData); + } else { + return NULL_VALUE_ERROR; + } + if (ret_val != NONE_ERROR) { + return ret_val; + } + } else { + return NULL_VALUE_ERROR; + } + } + + va_end(pArgs); + snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument) - 1, remSizeOfJsonBuffer, "},"); + ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer); + return ret_val; +} + + +int32_t FillWithClientTokenSize(char *pBufferToBeUpdatedWithClientToken, size_t maxSizeOfJsonDocument) { + int32_t snPrintfReturn; + snPrintfReturn = snprintf(pBufferToBeUpdatedWithClientToken, maxSizeOfJsonDocument, "%s-%d", mqttClientID, + clientTokenNum++); + + return snPrintfReturn; +} + +IoT_Error_t aws_iot_fill_with_client_token(char *pBufferToBeUpdatedWithClientToken, size_t maxSizeOfJsonDocument){ + + int32_t snPrintfRet = 0; + snPrintfRet = FillWithClientTokenSize(pBufferToBeUpdatedWithClientToken, maxSizeOfJsonDocument); + return checkReturnValueOfSnPrintf(snPrintfRet, maxSizeOfJsonDocument); + +} + +IoT_Error_t aws_iot_finalize_json_document(char *pJsonDocument, size_t maxSizeOfJsonDocument) { + size_t remSizeOfJsonBuffer = maxSizeOfJsonDocument; + int32_t snPrintfReturn = 0; + int32_t tempSize = 0; + IoT_Error_t ret_val = NONE_ERROR; + + if (pJsonDocument == NULL) { + return NULL_VALUE_ERROR; + } + + tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument); + if(tempSize <= 1){ + return SHADOW_JSON_ERROR; + } + remSizeOfJsonBuffer = tempSize; + + // strlen(ShadowTxBuffer) - 1 is to ensure we remove the last ,(comma) that was added + snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument) - 1, remSizeOfJsonBuffer, "}, \"%s\":\"", + SHADOW_CLIENT_TOKEN_STRING); + ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer); + + if (ret_val != NONE_ERROR) { + return ret_val; + } + // refactor this XXX repeated code + tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument); + if(tempSize <= 1){ + return SHADOW_JSON_ERROR; + } + remSizeOfJsonBuffer = tempSize; + + + snPrintfReturn = FillWithClientTokenSize(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer); + ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer); + + if (ret_val != NONE_ERROR) { + return ret_val; + } + tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument); + if(tempSize <= 1){ + return SHADOW_JSON_ERROR; + } + remSizeOfJsonBuffer = tempSize; + + + snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer, "\"}"); + ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer); + + return ret_val; +} + +void FillWithClientToken(char *pBufferToBeUpdatedWithClientToken) { + sprintf(pBufferToBeUpdatedWithClientToken, "%s-%d", mqttClientID, clientTokenNum++); +} + +static IoT_Error_t convertDataToString(char *pStringBuffer, size_t maxSizoStringBuffer, JsonPrimitiveType type, + void *pData) { + int32_t snPrintfReturn = 0; + IoT_Error_t ret_val = NONE_ERROR; + + if (maxSizoStringBuffer == 0) { + return SHADOW_JSON_ERROR; + } + + if (type == SHADOW_JSON_INT32) { + //snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIi32",", *(int32_t * )(pData)); + snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%li,", *(int32_t * )(pData)); + } else if (type == SHADOW_JSON_INT16) { + //snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIi16",", *(int16_t * )(pData)); + snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%i,", *(int16_t * )(pData)); + } else if (type == SHADOW_JSON_INT8) { + //snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIi8",", *(int8_t * )(pData)); + snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%i,", *(int8_t * )(pData)); + } else if (type == SHADOW_JSON_UINT32) { + //snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIu32",", *(uint32_t * )(pData)); + snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%lu,", *(uint32_t * )(pData)); + } else if (type == SHADOW_JSON_UINT16) { + //snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIu16",", *(uint16_t * )(pData)); + snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%u,", *(uint16_t * )(pData)); + } else if (type == SHADOW_JSON_UINT8) { + //snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIu8",", *(uint8_t * )(pData)); + snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%u,", *(uint8_t * )(pData)); + } else if (type == SHADOW_JSON_DOUBLE) { + snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%f,", *(double * )(pData)); + } else if (type == SHADOW_JSON_FLOAT) { + snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%f,", *(float * )(pData)); + } else if (type == SHADOW_JSON_BOOL) { + snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%s,", *(bool *)(pData)?"true":"false"); + } else if (type == SHADOW_JSON_STRING) { + snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "\"%s\",", (char * )(pData)); + } + + ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, maxSizoStringBuffer); + + return ret_val; +} +static jsmn_parser shadowJsonParser; +static jsmntok_t jsonTokenStruct[MAX_JSON_TOKEN_EXPECTED]; + +bool isJsonValidAndParse(const char *pJsonDocument, void *pJsonHandler, int32_t *pTokenCount) { + int32_t tokenCount; + + jsmn_init(&shadowJsonParser); + + tokenCount = jsmn_parse(&shadowJsonParser, pJsonDocument, strlen(pJsonDocument), jsonTokenStruct, + sizeof(jsonTokenStruct) / sizeof(jsonTokenStruct[0])); + + if (tokenCount < 0) { + WARN("Failed to parse JSON: %d\n", tokenCount); + return false; + } + + /* Assume the top-level element is an object */ + if (tokenCount < 1 || jsonTokenStruct[0].type != JSMN_OBJECT) { + WARN("Top Level is not an object\n"); + return false; + } + + pJsonHandler = (void *) jsonTokenStruct; + *pTokenCount = tokenCount; + + return true; +} + +static IoT_Error_t UpdateValueIfNoObject(const char *pJsonString, jsonStruct_t *pDataStruct, jsmntok_t token) { + IoT_Error_t ret_val = NONE_ERROR; + if (pDataStruct->type == SHADOW_JSON_BOOL) { + ret_val = parseBooleanValue((bool *)pDataStruct->pData, pJsonString, &token); + } else if (pDataStruct->type == SHADOW_JSON_INT32) { + ret_val = parseInteger32Value((int32_t *)pDataStruct->pData, pJsonString, &token); + } else if (pDataStruct->type == SHADOW_JSON_INT16) { + ret_val = parseInteger16Value((int16_t *)pDataStruct->pData, pJsonString, &token); + } else if (pDataStruct->type == SHADOW_JSON_INT8) { + ret_val = parseInteger8Value((int8_t *)pDataStruct->pData, pJsonString, &token); + } else if (pDataStruct->type == SHADOW_JSON_UINT32) { + ret_val = parseUnsignedInteger32Value((uint32_t *)pDataStruct->pData, pJsonString, &token); + } else if (pDataStruct->type == SHADOW_JSON_UINT16) { + ret_val = parseUnsignedInteger16Value((uint16_t *)pDataStruct->pData, pJsonString, &token); + } else if (pDataStruct->type == SHADOW_JSON_UINT8) { + ret_val = parseUnsignedInteger8Value((uint8_t *)pDataStruct->pData, pJsonString, &token); + } else if (pDataStruct->type == SHADOW_JSON_FLOAT) { + ret_val = parseFloatValue((float *)pDataStruct->pData, pJsonString, &token); + } else if (pDataStruct->type == SHADOW_JSON_DOUBLE) { + ret_val = parseDoubleValue((double *)pDataStruct->pData, pJsonString, &token); + } + + return ret_val; +} + +bool isJsonKeyMatchingAndUpdateValue(const char *pJsonDocument, void *pJsonHandler, int32_t tokenCount, + jsonStruct_t *pDataStruct, uint32_t *pDataLength, int32_t *pDataPosition) { + int32_t i; + + jsmntok_t *pJsonTokenStruct; + + pJsonTokenStruct = (jsmntok_t *) pJsonHandler; + for (i = 1; i < tokenCount; i++) { + if (jsoneq(pJsonDocument, &(jsonTokenStruct[i]), pDataStruct->pKey) == 0) { + jsmntok_t dataToken = jsonTokenStruct[i + 1]; + uint32_t dataLength = dataToken.end - dataToken.start; + UpdateValueIfNoObject(pJsonDocument, pDataStruct, dataToken); + *pDataPosition = dataToken.start; + *pDataLength = dataLength; + return true; + } + } + return false; +} + +bool isReceivedJsonValid(const char *pJsonDocument) { + int32_t tokenCount; + + jsmn_init(&shadowJsonParser); + + tokenCount = jsmn_parse(&shadowJsonParser, pJsonDocument, strlen(pJsonDocument), jsonTokenStruct, + sizeof(jsonTokenStruct) / sizeof(jsonTokenStruct[0])); + + if (tokenCount < 0) { + WARN("Failed to parse JSON: %d\n", tokenCount); + return false; + } + + /* Assume the top-level element is an object */ + if (tokenCount < 1 || jsonTokenStruct[0].type != JSMN_OBJECT) { + return false; + } + + return true; +} + +bool extractClientToken(const char *pJsonDocument, char *pExtractedClientToken) { + bool ret_val = false; + jsmn_init(&shadowJsonParser); + int32_t tokenCount, i; + jsmntok_t ClientJsonToken; + + tokenCount = jsmn_parse(&shadowJsonParser, pJsonDocument, strlen(pJsonDocument), jsonTokenStruct, + sizeof(jsonTokenStruct) / sizeof(jsonTokenStruct[0])); + + if (tokenCount < 0) { + WARN("Failed to parse JSON: %d\n", tokenCount); + return false; + } + + /* Assume the top-level element is an object */ + if (tokenCount < 1 || jsonTokenStruct[0].type != JSMN_OBJECT) { + return false; + } + + for (i = 1; i < tokenCount; i++) { + if (jsoneq(pJsonDocument, &jsonTokenStruct[i], SHADOW_CLIENT_TOKEN_STRING) == 0) { + ClientJsonToken = jsonTokenStruct[i + 1]; + uint8_t length = ClientJsonToken.end - ClientJsonToken.start; + strncpy(pExtractedClientToken, pJsonDocument + ClientJsonToken.start, length); + pExtractedClientToken[length] = '\0'; + return true; + } + } + + return false; +} + +bool extractVersionNumber(const char *pJsonDocument, void *pJsonHandler, int32_t tokenCount, uint32_t *pVersionNumber) { + int32_t i; + jsmntok_t *pJsonTokenStruct; + IoT_Error_t ret_val = NONE_ERROR; + + pJsonTokenStruct = (jsmntok_t *) pJsonHandler; + for (i = 1; i < tokenCount; i++) { + if (jsoneq(pJsonDocument, &(jsonTokenStruct[i]), SHADOW_VERSION_STRING) == 0) { + jsmntok_t dataToken = jsonTokenStruct[i + 1]; + uint32_t dataLength = dataToken.end - dataToken.start; + ret_val = parseUnsignedInteger32Value(pVersionNumber, pJsonDocument, &dataToken); + if (ret_val == NONE_ERROR) { + return true; + } + } + } + return false; +} + +