Demo application for using the AT&T IoT Starter Kit Powered by AWS.

Dependencies:   SDFileSystem

Fork of ATT_AWS_IoT_demo by Anthony Phillips

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers aws_iot_shadow_json.cpp Source File

aws_iot_shadow_json.cpp

00001 /*
00002  * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License").
00005  * You may not use this file except in compliance with the License.
00006  * A copy of the License is located at
00007  *
00008  *  http://aws.amazon.com/apache2.0
00009  *
00010  * or in the "license" file accompanying this file. This file is distributed
00011  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
00012  * express or implied. See the License for the specific language governing
00013  * permissions and limitations under the License.
00014  */
00015 
00016 #include "aws_iot_shadow_json.h"
00017 
00018 #include <string.h>
00019 #include <stdbool.h>
00020 #include <inttypes.h>
00021 #include "aws_iot_json_utils.h"
00022 #include "aws_iot_log.h"
00023 #include "aws_iot_shadow_key.h"
00024 #include "aws_iot_config.h"
00025 
00026 extern char mqttClientID[MAX_SIZE_OF_UNIQUE_CLIENT_ID_BYTES];
00027 
00028 static uint32_t clientTokenNum = 0;
00029 
00030 //helper functions
00031 static IoT_Error_t convertDataToString(char *pStringBuffer, size_t maxSizoStringBuffer, JsonPrimitiveType type,
00032         void *pData);
00033 
00034 void resetClientTokenSequenceNum(void) {
00035     clientTokenNum = 0;
00036 }
00037 
00038 static void emptyJsonWithClientToken(char *pJsonDocument) {
00039     sprintf(pJsonDocument, "{\"clientToken\":\"");
00040     FillWithClientToken(pJsonDocument + strlen(pJsonDocument));
00041     sprintf(pJsonDocument + strlen(pJsonDocument), "\"}");
00042 }
00043 
00044 void iot_shadow_get_request_json(char *pJsonDocument) {
00045     emptyJsonWithClientToken(pJsonDocument);
00046 }
00047 
00048 void iot_shadow_delete_request_json(char *pJsonDocument) {
00049     emptyJsonWithClientToken(pJsonDocument);
00050 }
00051 
00052 static inline IoT_Error_t checkReturnValueOfSnPrintf(int32_t snPrintfReturn, size_t maxSizeOfJsonDocument) {
00053 
00054     if (snPrintfReturn >= maxSizeOfJsonDocument) {
00055         return SHADOW_JSON_BUFFER_TRUNCATED;
00056     } else if (snPrintfReturn < 0) {
00057         return SHADOW_JSON_ERROR;
00058     }
00059     return NONE_ERROR;
00060 }
00061 
00062 IoT_Error_t aws_iot_shadow_init_json_document(char *pJsonDocument, size_t maxSizeOfJsonDocument) {
00063 
00064     IoT_Error_t ret_val = NONE_ERROR;
00065     int32_t snPrintfReturn = 0;
00066 
00067     if (pJsonDocument == NULL) {
00068         return NULL_VALUE_ERROR;
00069     }
00070     snPrintfReturn = snprintf(pJsonDocument, maxSizeOfJsonDocument, "{\"state\":{");
00071 
00072     ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, maxSizeOfJsonDocument);
00073 
00074     return ret_val;
00075 
00076 }
00077 
00078 IoT_Error_t aws_iot_shadow_add_desired(char *pJsonDocument, size_t maxSizeOfJsonDocument, uint8_t count, ...) {
00079     IoT_Error_t ret_val = NONE_ERROR;
00080     int32_t tempSize = 0;
00081     int8_t i;
00082     size_t remSizeOfJsonBuffer = maxSizeOfJsonDocument;
00083     int32_t snPrintfReturn = 0;
00084     va_list pArgs;
00085     va_start(pArgs, count);
00086     jsonStruct_t *pTemporary;
00087 
00088     if (pJsonDocument == NULL) {
00089         return NULL_VALUE_ERROR;
00090     }
00091 
00092     tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
00093         if(tempSize <= 1){
00094             return SHADOW_JSON_ERROR;
00095         }
00096         remSizeOfJsonBuffer = tempSize;
00097 
00098     snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer, "\"desired\":{");
00099     ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
00100 
00101     if (ret_val != NONE_ERROR) {
00102         return ret_val;
00103     }
00104 
00105     for (i = 0; i < count; i++) {
00106         tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
00107             if(tempSize <= 1){
00108                 return SHADOW_JSON_ERROR;
00109             }
00110             remSizeOfJsonBuffer = tempSize;
00111         pTemporary = va_arg (pArgs, jsonStruct_t *);
00112         if (pTemporary != NULL) {
00113             snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer, "\"%s\":",
00114                     pTemporary->pKey);
00115             ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
00116             if (ret_val != NONE_ERROR) {
00117                 return ret_val;
00118             }
00119             if (pTemporary->pKey != NULL && pTemporary->pData != NULL) {
00120                 ret_val = convertDataToString(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer,
00121                         pTemporary->type, pTemporary->pData);
00122             } else {
00123                 return NULL_VALUE_ERROR;
00124             }
00125             if (ret_val != NONE_ERROR) {
00126                 return ret_val;
00127             }
00128         } else {
00129             return NULL_VALUE_ERROR;
00130         }
00131     }
00132 
00133     va_end(pArgs);
00134     snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument) - 1, remSizeOfJsonBuffer, "},");
00135     ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
00136     return ret_val;
00137 }
00138 
00139 IoT_Error_t aws_iot_shadow_add_reported(char *pJsonDocument, size_t maxSizeOfJsonDocument, uint8_t count, ...) {
00140     IoT_Error_t ret_val = NONE_ERROR;
00141 
00142     int8_t i;
00143     size_t remSizeOfJsonBuffer = maxSizeOfJsonDocument;
00144     int32_t snPrintfReturn = 0;
00145     int32_t tempSize = 0;
00146     va_list pArgs;
00147     va_start(pArgs, count);
00148     jsonStruct_t *pTemporary;
00149 
00150     if (pJsonDocument == NULL) {
00151         return NULL_VALUE_ERROR;
00152     }
00153 
00154 
00155     tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
00156     if(tempSize <= 1){
00157         return SHADOW_JSON_ERROR;
00158     }
00159     remSizeOfJsonBuffer = tempSize;
00160 
00161     snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer, "\"reported\":{");
00162     ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
00163 
00164     if (ret_val != NONE_ERROR) {
00165         return ret_val;
00166     }
00167 
00168     for (i = 0; i < count; i++) {
00169         tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
00170         if(tempSize <= 1){
00171             return SHADOW_JSON_ERROR;
00172         }
00173         remSizeOfJsonBuffer = tempSize;
00174 
00175         pTemporary = va_arg (pArgs, jsonStruct_t *);
00176         if (pTemporary != NULL) {
00177             snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer, "\"%s\":",
00178                     pTemporary->pKey);
00179             ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
00180             if (ret_val != NONE_ERROR) {
00181                 return ret_val;
00182             }
00183             if (pTemporary->pKey != NULL && pTemporary->pData != NULL) {
00184                 ret_val = convertDataToString(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer,
00185                         pTemporary->type, pTemporary->pData);
00186             } else {
00187                 return NULL_VALUE_ERROR;
00188             }
00189             if (ret_val != NONE_ERROR) {
00190                 return ret_val;
00191             }
00192         } else {
00193             return NULL_VALUE_ERROR;
00194         }
00195     }
00196 
00197     va_end(pArgs);
00198     snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument) - 1, remSizeOfJsonBuffer, "},");
00199     ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
00200     return ret_val;
00201 }
00202 
00203 
00204 int32_t FillWithClientTokenSize(char *pBufferToBeUpdatedWithClientToken, size_t maxSizeOfJsonDocument) {
00205     int32_t snPrintfReturn;
00206     snPrintfReturn = snprintf(pBufferToBeUpdatedWithClientToken, maxSizeOfJsonDocument, "%s-%d", mqttClientID,
00207             clientTokenNum++);
00208 
00209     return snPrintfReturn;
00210 }
00211 
00212 IoT_Error_t aws_iot_fill_with_client_token(char *pBufferToBeUpdatedWithClientToken, size_t maxSizeOfJsonDocument){
00213 
00214     int32_t snPrintfRet = 0;
00215     snPrintfRet = FillWithClientTokenSize(pBufferToBeUpdatedWithClientToken, maxSizeOfJsonDocument);
00216     return checkReturnValueOfSnPrintf(snPrintfRet, maxSizeOfJsonDocument);
00217 
00218 }
00219 
00220 IoT_Error_t aws_iot_finalize_json_document(char *pJsonDocument, size_t maxSizeOfJsonDocument) {
00221     size_t remSizeOfJsonBuffer = maxSizeOfJsonDocument;
00222     int32_t snPrintfReturn = 0;
00223     int32_t tempSize = 0;
00224     IoT_Error_t ret_val = NONE_ERROR;
00225 
00226     if (pJsonDocument == NULL) {
00227         return NULL_VALUE_ERROR;
00228     }
00229 
00230     tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
00231     if(tempSize <= 1){
00232         return SHADOW_JSON_ERROR;
00233     }
00234     remSizeOfJsonBuffer = tempSize;
00235 
00236     // strlen(ShadowTxBuffer) - 1 is to ensure we remove the last ,(comma) that was added
00237     snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument) - 1, remSizeOfJsonBuffer, "}, \"%s\":\"",
00238             SHADOW_CLIENT_TOKEN_STRING);
00239     ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
00240 
00241     if (ret_val != NONE_ERROR) {
00242         return ret_val;
00243     }
00244     // refactor this XXX repeated code
00245     tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
00246     if(tempSize <= 1){
00247         return SHADOW_JSON_ERROR;
00248     }
00249     remSizeOfJsonBuffer = tempSize;
00250 
00251 
00252     snPrintfReturn = FillWithClientTokenSize(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer);
00253     ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
00254 
00255     if (ret_val != NONE_ERROR) {
00256         return ret_val;
00257     }
00258     tempSize = maxSizeOfJsonDocument - strlen(pJsonDocument);
00259     if(tempSize <= 1){
00260         return SHADOW_JSON_ERROR;
00261     }
00262     remSizeOfJsonBuffer = tempSize;
00263 
00264 
00265     snPrintfReturn = snprintf(pJsonDocument + strlen(pJsonDocument), remSizeOfJsonBuffer, "\"}");
00266     ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, remSizeOfJsonBuffer);
00267 
00268     return ret_val;
00269 }
00270 
00271 void FillWithClientToken(char *pBufferToBeUpdatedWithClientToken) {
00272     sprintf(pBufferToBeUpdatedWithClientToken, "%s-%d", mqttClientID, clientTokenNum++);
00273 }
00274 
00275 static IoT_Error_t convertDataToString(char *pStringBuffer, size_t maxSizoStringBuffer, JsonPrimitiveType type,
00276         void *pData) {
00277     int32_t snPrintfReturn = 0;
00278     IoT_Error_t ret_val = NONE_ERROR;
00279 
00280     if (maxSizoStringBuffer == 0) {
00281         return SHADOW_JSON_ERROR;
00282     }
00283 
00284     if (type == SHADOW_JSON_INT32) {
00285         //snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIi32",", *(int32_t * )(pData));
00286         snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%li,", *(int32_t * )(pData));
00287     } else if (type == SHADOW_JSON_INT16) {
00288         //snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIi16",", *(int16_t * )(pData));
00289         snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%i,", *(int16_t * )(pData));
00290     } else if (type == SHADOW_JSON_INT8) {
00291         //snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIi8",", *(int8_t * )(pData));
00292         snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%i,", *(int8_t * )(pData));
00293     } else if (type == SHADOW_JSON_UINT32) {
00294         //snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIu32",", *(uint32_t * )(pData));
00295         snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%lu,", *(uint32_t * )(pData));
00296     } else if (type == SHADOW_JSON_UINT16) {
00297         //snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIu16",", *(uint16_t * )(pData));
00298         snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%u,", *(uint16_t * )(pData));
00299     } else if (type == SHADOW_JSON_UINT8) {
00300         //snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%"PRIu8",", *(uint8_t * )(pData));
00301         snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%u,", *(uint8_t * )(pData));
00302     } else if (type == SHADOW_JSON_DOUBLE) {
00303         snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%f,", *(double * )(pData));
00304     } else if (type == SHADOW_JSON_FLOAT) {
00305         snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%f,", *(float * )(pData));
00306     } else if (type == SHADOW_JSON_BOOL) {
00307         snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "%s,", *(bool *)(pData)?"true":"false");
00308     } else if (type == SHADOW_JSON_STRING) {
00309         snPrintfReturn = snprintf(pStringBuffer, maxSizoStringBuffer, "\"%s\",", (char * )(pData));
00310     }
00311 
00312     ret_val = checkReturnValueOfSnPrintf(snPrintfReturn, maxSizoStringBuffer);
00313 
00314     return ret_val;
00315 }
00316 static jsmn_parser shadowJsonParser;
00317 static jsmntok_t jsonTokenStruct[MAX_JSON_TOKEN_EXPECTED];
00318 
00319 bool isJsonValidAndParse(const char *pJsonDocument, void *pJsonHandler, int32_t *pTokenCount) {
00320     int32_t tokenCount;
00321 
00322     jsmn_init(&shadowJsonParser);
00323 
00324     tokenCount = jsmn_parse(&shadowJsonParser, pJsonDocument, strlen(pJsonDocument), jsonTokenStruct,
00325             sizeof(jsonTokenStruct) / sizeof(jsonTokenStruct[0]));
00326 
00327     if (tokenCount < 0) {
00328         WARN("Failed to parse JSON: %d\n", tokenCount);
00329         return false;
00330     }
00331 
00332     /* Assume the top-level element is an object */
00333     if (tokenCount < 1 || jsonTokenStruct[0].type != JSMN_OBJECT) {
00334         WARN("Top Level is not an object\n");
00335         return false;
00336     }
00337 
00338     pJsonHandler = (void *) jsonTokenStruct;
00339     *pTokenCount = tokenCount;
00340 
00341     return true;
00342 }
00343 
00344 static IoT_Error_t UpdateValueIfNoObject(const char *pJsonString, jsonStruct_t *pDataStruct, jsmntok_t token) {
00345     IoT_Error_t ret_val = NONE_ERROR;
00346     if (pDataStruct->type == SHADOW_JSON_BOOL) {
00347         ret_val = parseBooleanValue((bool *)pDataStruct->pData, pJsonString, &token);
00348     } else if (pDataStruct->type == SHADOW_JSON_INT32) {
00349         ret_val = parseInteger32Value((int32_t *)pDataStruct->pData, pJsonString, &token);
00350     } else if (pDataStruct->type == SHADOW_JSON_INT16) {
00351         ret_val = parseInteger16Value((int16_t *)pDataStruct->pData, pJsonString, &token);
00352     } else if (pDataStruct->type == SHADOW_JSON_INT8) {
00353         ret_val = parseInteger8Value((int8_t *)pDataStruct->pData, pJsonString, &token);
00354     } else if (pDataStruct->type == SHADOW_JSON_UINT32) {
00355         ret_val = parseUnsignedInteger32Value((uint32_t *)pDataStruct->pData, pJsonString, &token);
00356     } else if (pDataStruct->type == SHADOW_JSON_UINT16) {
00357         ret_val = parseUnsignedInteger16Value((uint16_t *)pDataStruct->pData, pJsonString, &token);
00358     } else if (pDataStruct->type == SHADOW_JSON_UINT8) {
00359         ret_val = parseUnsignedInteger8Value((uint8_t *)pDataStruct->pData, pJsonString, &token);
00360     } else if (pDataStruct->type == SHADOW_JSON_FLOAT) {
00361         ret_val = parseFloatValue((float *)pDataStruct->pData, pJsonString, &token);
00362     } else if (pDataStruct->type == SHADOW_JSON_DOUBLE) {
00363         ret_val = parseDoubleValue((double *)pDataStruct->pData, pJsonString, &token);
00364     }
00365 
00366     return ret_val;
00367 }
00368 
00369 bool isJsonKeyMatchingAndUpdateValue(const char *pJsonDocument, void *pJsonHandler, int32_t tokenCount,
00370         jsonStruct_t *pDataStruct, uint32_t *pDataLength, int32_t *pDataPosition) {
00371     int32_t i;
00372 
00373     jsmntok_t *pJsonTokenStruct;
00374 
00375     pJsonTokenStruct = (jsmntok_t *) pJsonHandler;
00376     for (i = 1; i < tokenCount; i++) {
00377         if (jsoneq(pJsonDocument, &(jsonTokenStruct[i]), pDataStruct->pKey) == 0) {
00378             jsmntok_t dataToken = jsonTokenStruct[i + 1];
00379             uint32_t dataLength = dataToken.end - dataToken.start;
00380             UpdateValueIfNoObject(pJsonDocument, pDataStruct, dataToken);
00381             *pDataPosition = dataToken.start;
00382             *pDataLength = dataLength;
00383             return true;
00384         }
00385     }
00386     return false;
00387 }
00388 
00389 bool isReceivedJsonValid(const char *pJsonDocument) {
00390     int32_t tokenCount;
00391 
00392     jsmn_init(&shadowJsonParser);
00393 
00394     tokenCount = jsmn_parse(&shadowJsonParser, pJsonDocument, strlen(pJsonDocument), jsonTokenStruct,
00395             sizeof(jsonTokenStruct) / sizeof(jsonTokenStruct[0]));
00396 
00397     if (tokenCount < 0) {
00398         WARN("Failed to parse JSON: %d\n", tokenCount);
00399         return false;
00400     }
00401 
00402     /* Assume the top-level element is an object */
00403     if (tokenCount < 1 || jsonTokenStruct[0].type != JSMN_OBJECT) {
00404         return false;
00405     }
00406 
00407     return true;
00408 }
00409 
00410 bool extractClientToken(const char *pJsonDocument, char *pExtractedClientToken) {
00411     bool ret_val = false;
00412     jsmn_init(&shadowJsonParser);
00413     int32_t tokenCount, i;
00414     jsmntok_t ClientJsonToken;
00415 
00416     tokenCount = jsmn_parse(&shadowJsonParser, pJsonDocument, strlen(pJsonDocument), jsonTokenStruct,
00417             sizeof(jsonTokenStruct) / sizeof(jsonTokenStruct[0]));
00418 
00419     if (tokenCount < 0) {
00420         WARN("Failed to parse JSON: %d\n", tokenCount);
00421         return false;
00422     }
00423 
00424     /* Assume the top-level element is an object */
00425     if (tokenCount < 1 || jsonTokenStruct[0].type != JSMN_OBJECT) {
00426         return false;
00427     }
00428 
00429     for (i = 1; i < tokenCount; i++) {
00430         if (jsoneq(pJsonDocument, &jsonTokenStruct[i], SHADOW_CLIENT_TOKEN_STRING) == 0) {
00431             ClientJsonToken = jsonTokenStruct[i + 1];
00432             uint8_t length = ClientJsonToken.end - ClientJsonToken.start;
00433             strncpy(pExtractedClientToken, pJsonDocument + ClientJsonToken.start, length);
00434             pExtractedClientToken[length] = '\0';
00435             return true;
00436         }
00437     }
00438 
00439     return false;
00440 }
00441 
00442 bool extractVersionNumber(const char *pJsonDocument, void *pJsonHandler, int32_t tokenCount, uint32_t *pVersionNumber) {
00443     int32_t i;
00444     jsmntok_t *pJsonTokenStruct;
00445     IoT_Error_t ret_val = NONE_ERROR;
00446 
00447     pJsonTokenStruct = (jsmntok_t *) pJsonHandler;
00448     for (i = 1; i < tokenCount; i++) {
00449         if (jsoneq(pJsonDocument, &(jsonTokenStruct[i]), SHADOW_VERSION_STRING) == 0) {
00450             jsmntok_t dataToken = jsonTokenStruct[i + 1];
00451             uint32_t dataLength = dataToken.end - dataToken.start;
00452             ret_val = parseUnsignedInteger32Value(pVersionNumber, pJsonDocument, &dataToken);
00453             if (ret_val == NONE_ERROR) {
00454                 return true;
00455             }
00456         }
00457     }
00458     return false;
00459 }
00460 
00461