├── tools ├── create_thing │ ├── tests │ │ ├── __init__.py │ │ └── test_create_thing.py │ ├── create_thing │ │ ├── __init__.py │ │ └── create_thing.py │ ├── pyproject.toml │ ├── README.md │ └── poetry.lock ├── Pipfile └── Pipfile.lock ├── component.mk ├── .gitignore ├── examples ├── pubSubTest │ ├── README.md │ ├── pubSubTest.ino │ └── config.h-dist └── iam │ └── thing_policy_full_permissions.json ├── library.properties ├── Makefile ├── .github └── workflows │ └── test.yml ├── platformio.ini ├── src ├── aws_iot_shadow_key.h ├── timer_platform.h ├── aws_iot_shadow_actions.h ├── threads_platform.h ├── aws_iot_version.h ├── aws_iot_shadow_json.h ├── network_platform.h ├── aws_iot_shadow_records.h ├── jsonParser.h ├── AWS_IOT.h ├── aws_iot_jobs_types.c ├── aws_iot_shadow_actions.c ├── timer.c ├── aws_iot_jobs_topics.h ├── aws_iot_jobs_types.h ├── threads_freertos.c ├── timer_interface.h ├── threads_interface.h ├── aws_iot_log.h ├── aws_iot_jobs_topics.c ├── aws_iot_jobs_json.h ├── aws_iot_config.h ├── aws_iot_mqtt_client_common_internal.h ├── aws_iot_jobs_json.c ├── aws_iot_json_utils.c ├── aws_iot_shadow_json_data.h ├── aws_iot_json_utils.h ├── network_interface.h ├── aws_iot_error.h ├── aws_iot_jobs_interface.c ├── aws_iot_shadow.c ├── aws_iot_mqtt_client_interface.h ├── AWS_IOT.cpp ├── aws_iot_mqtt_client_unsubscribe.c ├── aws_iot_jobs_interface.h ├── jsonParser.cpp └── aws_iot_mqtt_client_yield.c └── README.md /tools/create_thing/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /component.mk: -------------------------------------------------------------------------------- 1 | COMPONENT_ADD_INCLUDEDIRS := src 2 | -------------------------------------------------------------------------------- /tools/create_thing/create_thing/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = '0.1.0' 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *~ 3 | examples/**/config.h 4 | .pioenvs/ 5 | **/*.pem 6 | .pio/ 7 | __pycache__ 8 | tools/create_thing/create_thing.egg-info/ 9 | -------------------------------------------------------------------------------- /examples/pubSubTest/README.md: -------------------------------------------------------------------------------- 1 | # Basic PubSub Example 2 | 3 | * copy `config.h-dist` to `config.h` and update your WiFi configuration, 4 | AWS certificates and MQTT details 5 | * compile, upload and run sketch 6 | 7 | 8 | -------------------------------------------------------------------------------- /tools/Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [dev-packages] 7 | 8 | [packages] 9 | "boto3" = "*" 10 | 11 | [requires] 12 | python_version = "2.7" 13 | -------------------------------------------------------------------------------- /tools/create_thing/tests/test_create_thing.py: -------------------------------------------------------------------------------- 1 | from create_thing.create_thing import string_as_c_literal 2 | 3 | 4 | def test_string_as_c_literal(): 5 | assert '"line 1\\n"\n"line 2\\n"' == string_as_c_literal( "line 1\nline 2" ) 6 | 7 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=ESP32AwsIotCore 2 | version=1.0.0 3 | author=Jan Delgado 4 | maintainer=Jan Delgado 5 | sentence=Use AWS IoT with the ESP32 6 | paragraph=Easily attach your ESP32 to the AWS IoT cloud. Derived from hornbill examples. 7 | category=Data Processing 8 | url=https://github.com/jandelgado/esp32-aws-iot 9 | architectures=esp32 10 | includes=AWS_IOT.h 11 | 12 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: ci run clean upload monitor tags 2 | 3 | CIOPTS=--board=esp32dev --lib="src" 4 | 5 | ci: 6 | cp -n examples/pubSubTest/config.h-dist examples/pubSubTest/config.h 7 | platformio ci $(CIOPTS) --lib=examples/pubSubTest examples/pubSubTest/pubSubTest.ino 8 | 9 | run: 10 | pio run 11 | 12 | clean: 13 | -pio run --target clean 14 | rm -f src/*.o 15 | 16 | upload: 17 | pio run --target upload 18 | 19 | monitor: 20 | pio device monitor 21 | 22 | tags: 23 | ctags -R 24 | -------------------------------------------------------------------------------- /examples/iam/thing_policy_full_permissions.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [{ 4 | "Action": [ 5 | "iot:Publish", 6 | "iot:Connect", 7 | "iot:Receive", 8 | "iot:Subscribe", 9 | "iot:GetThingShadow", 10 | "iot:DeleteThingShadow", 11 | "iot:UpdateThingShadow" 12 | ], 13 | "Effect": "Allow", 14 | "Resource": [ 15 | "*" 16 | ] 17 | }] 18 | } 19 | -------------------------------------------------------------------------------- /tools/create_thing/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "create_thing" 3 | version = "0.1.0" 4 | description = "create AWS IoT things to use with embedded devices" 5 | authors = ["Jan Delgado "] 6 | 7 | [tool.poetry.scripts] 8 | create_thing = 'create_thing.create_thing:run' 9 | 10 | [tool.poetry.dependencies] 11 | python = "^3.8" 12 | boto3 = "^1.14.23" 13 | 14 | [tool.poetry.dev-dependencies] 15 | pytest = "^5.2" 16 | 17 | [build-system] 18 | requires = ["poetry>=0.12"] 19 | build-backend = "poetry.masonry.api" 20 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - master 5 | pull_request: 6 | branches: 7 | - master 8 | 9 | name: run tests 10 | jobs: 11 | test: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: checkout code 15 | uses: actions/checkout@v2 16 | 17 | - name: install python 18 | uses: actions/setup-python@v2 19 | with: 20 | python-version: '3.8' 21 | 22 | - name: install platformio 23 | run: pip install platformio==5.0.3 24 | 25 | - name: build 26 | run: make ci 27 | 28 | -------------------------------------------------------------------------------- /platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; http://docs.platformio.org/page/projectconf.html 10 | 11 | [platformio] 12 | env_default = esp32 13 | src_dir = examples/pubSubTest 14 | 15 | [env:esp32] 16 | platform = espressif32 17 | board = esp32dev 18 | framework = arduino 19 | src_filter = +<../../src/> +<./> 20 | build_flags = -Isrc 21 | -------------------------------------------------------------------------------- /src/aws_iot_shadow_key.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | #ifndef SRC_SHADOW_AWS_IOT_SHADOW_KEY_H_ 17 | #define SRC_SHADOW_AWS_IOT_SHADOW_KEY_H_ 18 | 19 | #define SHADOW_CLIENT_TOKEN_STRING "clientToken" 20 | #define SHADOW_VERSION_STRING "version" 21 | 22 | #endif /* SRC_SHADOW_AWS_IOT_SHADOW_KEY_H_ */ 23 | -------------------------------------------------------------------------------- /tools/create_thing/README.md: -------------------------------------------------------------------------------- 1 | # create_thing.py 2 | 3 | This tool uses the AWS API (python/boto3) to create a thing, certificates and 4 | attach certificates and policies. In addition the script outputs 5 | ready-to-include C++ code to be included in your sketch. 6 | 7 | ## Usage 8 | 9 | ``` 10 | usage: create_thing.py [-h] [--type-name TYPE_NAME] name policy_name 11 | 12 | positional arguments: 13 | name name of the thing to create 14 | policy_name policy to attach thing to 15 | 16 | optional arguments: 17 | -h, --help show this help message and exit 18 | --type-name TYPE_NAME 19 | thing type name 20 | ``` 21 | 22 | ## Installation 23 | 24 | We use python and [poetry](https://python-poetry.org/): just run `poetry install` to install 25 | 26 | ## Author and copyright 27 | 28 | (C) Copyright 2019-2020 Jan Delgado 29 | 30 | ## License 31 | 32 | MIT 33 | -------------------------------------------------------------------------------- /src/timer_platform.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * Additions Copyright 2016 Espressif Systems (Shanghai) PTE LTD 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | #ifndef AWS_IOT_PLATFORM_H 18 | #define AWS_IOT_PLATFORM_H 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | #include 25 | #include "timer_interface.h" 26 | 27 | /** 28 | * definition of the Timer struct. Platform specific 29 | */ 30 | struct Timer { 31 | uint32_t start_ticks; 32 | uint32_t timeout_ticks; 33 | uint32_t last_polled_ticks; 34 | }; 35 | 36 | #ifdef __cplusplus 37 | } 38 | #endif 39 | 40 | #endif /* AWS_IOT_PLATFORM_H */ 41 | -------------------------------------------------------------------------------- /src/aws_iot_shadow_actions.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | #ifndef SRC_SHADOW_AWS_IOT_SHADOW_ACTIONS_H_ 17 | #define SRC_SHADOW_AWS_IOT_SHADOW_ACTIONS_H_ 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | #include "aws_iot_shadow_interface.h" 24 | 25 | IoT_Error_t aws_iot_shadow_internal_action(const char *pThingName, ShadowActions_t action, 26 | const char *pJsonDocumentToBeSent, size_t jsonSize, fpActionCallback_t callback, 27 | void *pCallbackContext, uint32_t timeout_seconds, bool isSticky); 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif 32 | 33 | #endif /* SRC_SHADOW_AWS_IOT_SHADOW_ACTIONS_H_ */ 34 | -------------------------------------------------------------------------------- /src/threads_platform.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * Additions Copyright 2016 Espressif Systems (Shanghai) PTE LTD 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | #include "threads_interface.h" 18 | 19 | #ifndef AWS_IOTSDK_THREADS_PLATFORM_H 20 | #define AWS_IOTSDK_THREADS_PLATFORM_H 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | #include "freertos/FreeRTOS.h" 27 | #include "freertos/semphr.h" 28 | 29 | /** 30 | * @brief Mutex Type 31 | * 32 | * definition of the Mutex struct. Platform specific 33 | * 34 | */ 35 | struct _IoT_Mutex_t { 36 | SemaphoreHandle_t mutex; 37 | }; 38 | 39 | #ifdef __cplusplus 40 | } 41 | #endif 42 | 43 | #endif /* AWS_IOTSDK_THREADS_PLATFORM_H */ 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/aws_iot_version.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | /** 17 | * @file aws_iot_version.h 18 | * @brief Constants defining the release version of the SDK. 19 | * 20 | * This file contains constants defining the release version of the SDK. 21 | * This file is modified by AWS upon release of the SDK and should not be 22 | * modified by the consumer of the SDK. The provided samples show example 23 | * usage of these constants. 24 | * 25 | * Versioning of the SDK follows the MAJOR.MINOR.PATCH Semantic Versioning guidelines. 26 | * @see http://semver.org/ 27 | */ 28 | #ifndef SRC_UTILS_AWS_IOT_VERSION_H_ 29 | #define SRC_UTILS_AWS_IOT_VERSION_H_ 30 | 31 | /** 32 | * @brief MAJOR version, incremented when incompatible API changes are made. 33 | */ 34 | #define VERSION_MAJOR 3 35 | /** 36 | * @brief MINOR version when functionality is added in a backwards-compatible manner. 37 | */ 38 | #define VERSION_MINOR 0 39 | /** 40 | * @brief PATCH version when backwards-compatible bug fixes are made. 41 | */ 42 | #define VERSION_PATCH 1 43 | /** 44 | * @brief TAG is an (optional) tag appended to the version if a more descriptive verion is needed. 45 | */ 46 | #define VERSION_TAG "" 47 | 48 | #endif /* SRC_UTILS_AWS_IOT_VERSION_H_ */ 49 | -------------------------------------------------------------------------------- /src/aws_iot_shadow_json.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | #ifndef AWS_IOT_SDK_SRC_IOT_SHADOW_JSON_H_ 16 | #define AWS_IOT_SDK_SRC_IOT_SHADOW_JSON_H_ 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "aws_iot_error.h" 27 | #include "aws_iot_shadow_json_data.h" 28 | 29 | bool isJsonValidAndParse(const char *pJsonDocument, size_t jsonSize, void *pJsonHandler, int32_t *pTokenCount); 30 | 31 | bool isJsonKeyMatchingAndUpdateValue(const char *pJsonDocument, void *pJsonHandler, int32_t tokenCount, 32 | jsonStruct_t *pDataStruct, uint32_t *pDataLength, int32_t *pDataPosition); 33 | 34 | IoT_Error_t aws_iot_shadow_internal_get_request_json(char *pBuffer, size_t bufferSize); 35 | 36 | IoT_Error_t aws_iot_shadow_internal_delete_request_json(char *pBuffer, size_t bufferSize); 37 | 38 | void resetClientTokenSequenceNum(void); 39 | 40 | 41 | bool isReceivedJsonValid(const char *pJsonDocument, size_t jsonSize); 42 | 43 | bool extractClientToken(const char *pJsonDocument, size_t jsonSize, char *pExtractedClientToken, size_t clientTokenSize); 44 | 45 | bool extractVersionNumber(const char *pJsonDocument, void *pJsonHandler, int32_t tokenCount, uint32_t *pVersionNumber); 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif 50 | 51 | #endif // AWS_IOT_SDK_SRC_IOT_SHADOW_JSON_H_ 52 | -------------------------------------------------------------------------------- /src/network_platform.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * Additions Copyright 2016 Espressif Systems (Shanghai) PTE LTD 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | #ifndef IOTSDKC_NETWORK_MBEDTLS_PLATFORM_H_H 18 | 19 | #if !defined(MBEDTLS_CONFIG_FILE) 20 | #include "mbedtls/config.h" 21 | #else 22 | #include MBEDTLS_CONFIG_FILE 23 | #endif 24 | 25 | #include "mbedtls/platform.h" 26 | #include "mbedtls/net.h" 27 | #include "mbedtls/ssl.h" 28 | #include "mbedtls/entropy.h" 29 | #include "mbedtls/ctr_drbg.h" 30 | #include "mbedtls/certs.h" 31 | #include "mbedtls/x509.h" 32 | #include "mbedtls/error.h" 33 | #include "mbedtls/debug.h" 34 | #include "mbedtls/timing.h" 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | /** 41 | * @brief TLS Connection Parameters 42 | * 43 | * Defines a type containing TLS specific parameters to be passed down to the 44 | * TLS networking layer to create a TLS secured socket. 45 | */ 46 | typedef struct _TLSDataParams { 47 | mbedtls_entropy_context entropy; 48 | mbedtls_ctr_drbg_context ctr_drbg; 49 | mbedtls_ssl_context ssl; 50 | mbedtls_ssl_config conf; 51 | uint32_t flags; 52 | mbedtls_x509_crt cacert; 53 | mbedtls_x509_crt clicert; 54 | mbedtls_pk_context pkey; 55 | mbedtls_net_context server_fd; 56 | }TLSDataParams; 57 | 58 | #define IOTSDKC_NETWORK_MBEDTLS_PLATFORM_H_H 59 | 60 | #ifdef __cplusplus 61 | } 62 | #endif 63 | 64 | #endif //IOTSDKC_NETWORK_MBEDTLS_PLATFORM_H_H 65 | -------------------------------------------------------------------------------- /src/aws_iot_shadow_records.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | #ifndef SRC_SHADOW_AWS_IOT_SHADOW_RECORDS_H_ 17 | #define SRC_SHADOW_AWS_IOT_SHADOW_RECORDS_H_ 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | #include 24 | 25 | #include "aws_iot_shadow_interface.h" 26 | #include "aws_iot_config.h" 27 | 28 | 29 | extern uint32_t shadowJsonVersionNum; 30 | extern bool shadowDiscardOldDeltaFlag; 31 | 32 | extern char myThingName[MAX_SIZE_OF_THING_NAME]; 33 | extern uint16_t myThingNameLen; 34 | extern char mqttClientID[MAX_SIZE_OF_UNIQUE_CLIENT_ID_BYTES]; 35 | extern uint16_t mqttClientIDLen; 36 | 37 | void initializeRecords(AWS_IoT_Client *pClient); 38 | bool isSubscriptionPresent(const char *pThingName, ShadowActions_t action); 39 | IoT_Error_t subscribeToShadowActionAcks(const char *pThingName, ShadowActions_t action, bool isSticky); 40 | void incrementSubscriptionCnt(const char *pThingName, ShadowActions_t action, bool isSticky); 41 | 42 | IoT_Error_t publishToShadowAction(const char *pThingName, ShadowActions_t action, const char *pJsonDocumentToBeSent); 43 | void addToAckWaitList(uint8_t indexAckWaitList, const char *pThingName, ShadowActions_t action, 44 | const char *pExtractedClientToken, fpActionCallback_t callback, void *pCallbackContext, 45 | uint32_t timeout_seconds); 46 | bool getNextFreeIndexOfAckWaitList(uint8_t *pIndex); 47 | void HandleExpiredResponseCallbacks(void); 48 | void initDeltaTokens(void); 49 | IoT_Error_t registerJsonTokenOnDelta(jsonStruct_t *pStruct); 50 | 51 | #ifdef __cplusplus 52 | } 53 | #endif 54 | 55 | #endif /* SRC_SHADOW_AWS_IOT_SHADOW_RECORDS_H_ */ 56 | -------------------------------------------------------------------------------- /examples/pubSubTest/pubSubTest.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // include your personal WiFi and AWS configuration. 5 | #include "config.h" 6 | 7 | AWS_IOT hornbill; 8 | 9 | int status = WL_IDLE_STATUS; 10 | int tick=0,msgCount=0,msgReceived = 0; 11 | char payload[512]; 12 | char rcvdPayload[512]; 13 | 14 | void mySubCallBackHandler (char *topicName, int payloadLen, char *payLoad) 15 | { 16 | strncpy(rcvdPayload,payLoad,payloadLen); 17 | rcvdPayload[payloadLen] = 0; 18 | msgReceived = 1; 19 | } 20 | 21 | 22 | 23 | void setup() { 24 | Serial.begin(9600); 25 | 26 | while (status != WL_CONNECTED) 27 | { 28 | Serial.print("Attempting to connect to SSID: "); 29 | Serial.println(WIFI_SSID); 30 | status = WiFi.begin(WIFI_SSID, WIFI_PASSWORD); 31 | delay(5000); 32 | } 33 | 34 | Serial.println("Connected to wifi"); 35 | 36 | if(hornbill.connect(HOST_ADDRESS, CLIENT_ID, 37 | aws_root_ca_pem, certificate_pem_crt, private_pem_key)== 0) 38 | { 39 | Serial.println("Connected to AWS"); 40 | delay(1000); 41 | 42 | if(0 == hornbill.subscribe(TOPIC_NAME,mySubCallBackHandler)) 43 | { 44 | Serial.println("Subscribe Successfull"); 45 | } 46 | else 47 | { 48 | Serial.println("Subscribe Failed, Check the Thing Name and Certificates. RESET."); 49 | while(1); 50 | } 51 | } 52 | else 53 | { 54 | Serial.println("AWS connection failed, Check the HOST Address. RESET."); 55 | while(1); 56 | } 57 | 58 | delay(2000); 59 | 60 | } 61 | 62 | void loop() { 63 | 64 | if(msgReceived == 1) 65 | { 66 | msgReceived = 0; 67 | Serial.print("Received Message:"); 68 | Serial.println(rcvdPayload); 69 | } 70 | if(tick >= 5) // publish to topic every 5seconds 71 | { 72 | tick=0; 73 | sprintf(payload,"Hello from hornbill ESP32 : %d",msgCount++); 74 | if(hornbill.publish(TOPIC_NAME,payload) == 0) 75 | { 76 | Serial.print("Publish Message:"); 77 | Serial.println(payload); 78 | } 79 | else 80 | { 81 | Serial.println("Publish failed"); 82 | } 83 | } 84 | vTaskDelay(1000 / portTICK_RATE_MS); 85 | tick++; 86 | } 87 | -------------------------------------------------------------------------------- /src/jsonParser.h: -------------------------------------------------------------------------------- 1 | #ifndef _JSON_PARSER_H_ 2 | #define _JSON_PARSER_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | /** 9 | * JSON type identifier. Basic types are: 10 | * o Object 11 | * o Array 12 | * o String 13 | * o Other primitive: number, boolean (true/false) or null 14 | */ 15 | typedef enum { 16 | JSMN_UNDEFINED = 0, 17 | JSMN_OBJECT = 1, 18 | JSMN_ARRAY = 2, 19 | JSMN_STRING = 3, 20 | JSMN_PRIMITIVE = 4 21 | } jsmntype_t; 22 | 23 | enum jsmnerr { 24 | /* Not enough tokens were provided */ 25 | JSMN_ERROR_NOMEM = -1, 26 | /* Invalid character inside JSON string */ 27 | JSMN_ERROR_INVAL = -2, 28 | /* The string is not a full JSON packet, more bytes expected */ 29 | JSMN_ERROR_PART = -3 30 | }; 31 | 32 | 33 | /** 34 | * JSON token description. 35 | * type type (object, array, string etc.) 36 | * start start position in JSON data string 37 | * end end position in JSON data string 38 | */ 39 | typedef struct { 40 | jsmntype_t type; 41 | int start; 42 | int end; 43 | int size; 44 | #ifdef JSMN_PARENT_LINKS 45 | int parent; 46 | #endif 47 | } jsmntok_t; 48 | 49 | /** 50 | * JSON parser. Contains an array of token blocks available. Also stores 51 | * the string being parsed now and current position in that string 52 | */ 53 | typedef struct { 54 | unsigned int pos; /* offset in the JSON string */ 55 | unsigned int toknext; /* next token to allocate */ 56 | int toksuper; /* superior token node, e.g parent object or array */ 57 | } jsmn_parser_t; 58 | 59 | 60 | class jsmnClass{ 61 | private : 62 | 63 | jsmntok_t* allocToken(jsmn_parser_t *tokenParser, jsmntok_t *tokens, size_t num_tokens); 64 | void fillToken(jsmntok_t *token, jsmntype_t type, int start, int end); 65 | int parsePrimitive(jsmn_parser_t *tokenParser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens); 66 | 67 | 68 | public: 69 | void Init(jsmn_parser_t *tokenParser); 70 | int equate(const char *json, jsmntok_t *tok, const char *s); 71 | int parse(jsmn_parser_t *tokenParser, const char *js, size_t len, jsmntok_t *tokens, unsigned int num_tokens); 72 | int parseString(jsmn_parser_t *tokenParser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens); 73 | 74 | }; 75 | 76 | extern jsmnClass jsmn; 77 | 78 | #ifdef __cplusplus 79 | } 80 | #endif 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /src/AWS_IOT.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | ExploreEmbedded Copyright Notice 3 | **************************************************************************************************** 4 | * File: AWS_IOT.h 5 | * Version: 1.0 6 | * Author: ExploreEmbedded 7 | * Website: http://www.exploreembedded.com/wiki 8 | * Description: ESP32 Arduino library for AWS IOT. 9 | 10 | This code has been developed and tested on ExploreEmbedded boards. 11 | We strongly believe that the library works on any of development boards for respective controllers. 12 | Check this link http://www.exploreembedded.com/wiki for awesome tutorials on 8051,PIC,AVR,ARM,Robotics,RTOS,IOT. 13 | ExploreEmbedded invests substantial time and effort developing open source HW and SW tools, to support consider buying the ExploreEmbedded boards. 14 | 15 | The ExploreEmbedded libraries and examples are licensed under the terms of the new-bsd license(two-clause bsd license). 16 | See also: http://www.opensource.org/licenses/bsd-license.php 17 | 18 | EXPLOREEMBEDDED DISCLAIMS ANY KIND OF HARDWARE FAILURE RESULTING OUT OF USAGE OF LIBRARIES, DIRECTLY OR 19 | INDIRECTLY. FILES MAY BE SUBJECT TO CHANGE WITHOUT PRIOR NOTICE. THE REVISION HISTORY CONTAINS THE INFORMATION 20 | RELATED TO UPDATES. 21 | 22 | 23 | Permission to use, copy, modify, and distribute this software and its documentation for any purpose 24 | and without fee is hereby granted, provided that this copyright notices appear in all copies 25 | and that both those copyright notices and this permission notice appear in supporting documentation. 26 | **************************************************************************************************/ 27 | 28 | 29 | #ifndef _HORNBILL_AWS_IOT_LIB_H_ 30 | #define _HORNBILL_AWS_IOT_LIB_H_ 31 | 32 | typedef void (*pSubCallBackHandler_t)(char *topicName, int payloadLen, char *payLoad); 33 | 34 | class AWS_IOT{ 35 | 36 | private: 37 | 38 | public: 39 | int connect(const char *hostAddress, const char *clientID, 40 | const char *aws_root_ca_pem, 41 | const char *certificate_pem_crt, 42 | const char *private_pem_key); 43 | int publish(const char *pubtopic, const char *pubPayLoad); 44 | int subscribe(const char *subTopic, pSubCallBackHandler_t pSubCallBackHandler); 45 | }; 46 | 47 | 48 | #endif 49 | 50 | -------------------------------------------------------------------------------- /src/aws_iot_jobs_types.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | #include 21 | #include "aws_iot_jobs_types.h" 22 | 23 | const char *JOB_EXECUTION_QUEUED_STR = "QUEUED"; 24 | const char *JOB_EXECUTION_IN_PROGRESS_STR = "IN_PROGRESS"; 25 | const char *JOB_EXECUTION_FAILED_STR = "FAILED"; 26 | const char *JOB_EXECUTION_SUCCEEDED_STR = "SUCCEEDED"; 27 | const char *JOB_EXECUTION_CANCELED_STR = "CANCELED"; 28 | const char *JOB_EXECUTION_REJECTED_STR = "REJECTED"; 29 | 30 | JobExecutionStatus aws_iot_jobs_map_string_to_job_status(const char *str) { 31 | if (str == NULL || str[0] == '\0') { 32 | return JOB_EXECUTION_STATUS_NOT_SET; 33 | } else if (strcmp(str, JOB_EXECUTION_QUEUED_STR) == 0) { 34 | return JOB_EXECUTION_QUEUED; 35 | } else if(strcmp(str, JOB_EXECUTION_IN_PROGRESS_STR) == 0) { 36 | return JOB_EXECUTION_IN_PROGRESS; 37 | } else if(strcmp(str, JOB_EXECUTION_FAILED_STR) == 0) { 38 | return JOB_EXECUTION_FAILED; 39 | } else if(strcmp(str, JOB_EXECUTION_SUCCEEDED_STR) == 0) { 40 | return JOB_EXECUTION_SUCCEEDED; 41 | } else if(strcmp(str, JOB_EXECUTION_CANCELED_STR) == 0) { 42 | return JOB_EXECUTION_CANCELED; 43 | } else if(strcmp(str, JOB_EXECUTION_REJECTED_STR) == 0) { 44 | return JOB_EXECUTION_REJECTED; 45 | } else { 46 | return JOB_EXECUTION_UNKNOWN_STATUS; 47 | } 48 | } 49 | 50 | const char *aws_iot_jobs_map_status_to_string(JobExecutionStatus status) { 51 | switch(status) { 52 | case JOB_EXECUTION_QUEUED: 53 | return JOB_EXECUTION_QUEUED_STR; 54 | case JOB_EXECUTION_IN_PROGRESS: 55 | return JOB_EXECUTION_IN_PROGRESS_STR; 56 | case JOB_EXECUTION_FAILED: 57 | return JOB_EXECUTION_FAILED_STR; 58 | case JOB_EXECUTION_SUCCEEDED: 59 | return JOB_EXECUTION_SUCCEEDED_STR; 60 | case JOB_EXECUTION_CANCELED: 61 | return JOB_EXECUTION_CANCELED_STR; 62 | case JOB_EXECUTION_REJECTED: 63 | return JOB_EXECUTION_REJECTED_STR; 64 | case JOB_EXECUTION_STATUS_NOT_SET: 65 | case JOB_EXECUTION_UNKNOWN_STATUS: 66 | default: 67 | return NULL; 68 | } 69 | } 70 | 71 | #ifdef __cplusplus 72 | } 73 | #endif 74 | -------------------------------------------------------------------------------- /src/aws_iot_shadow_actions.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | /** 17 | * @file aws_iot_shadow_actions.c 18 | * @brief Shadow client Action API definitions 19 | */ 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif 24 | 25 | #include "aws_iot_shadow_actions.h" 26 | 27 | #include "aws_iot_log.h" 28 | #include "aws_iot_shadow_json.h" 29 | #include "aws_iot_shadow_records.h" 30 | #include "aws_iot_config.h" 31 | 32 | IoT_Error_t aws_iot_shadow_internal_action(const char *pThingName, ShadowActions_t action, 33 | const char *pJsonDocumentToBeSent, size_t jsonSize, fpActionCallback_t callback, 34 | void *pCallbackContext, uint32_t timeout_seconds, bool isSticky) { 35 | IoT_Error_t ret_val = SUCCESS; 36 | bool isClientTokenPresent = false; 37 | bool isAckWaitListFree = false; 38 | uint8_t indexAckWaitList; 39 | char extractedClientToken[MAX_SIZE_CLIENT_ID_WITH_SEQUENCE]; 40 | 41 | FUNC_ENTRY; 42 | 43 | if(NULL == pThingName || NULL == pJsonDocumentToBeSent) { 44 | FUNC_EXIT_RC(NULL_VALUE_ERROR); 45 | } 46 | 47 | isClientTokenPresent = extractClientToken(pJsonDocumentToBeSent, jsonSize, extractedClientToken, MAX_SIZE_CLIENT_ID_WITH_SEQUENCE ); 48 | 49 | if(isClientTokenPresent && (NULL != callback)) { 50 | if(getNextFreeIndexOfAckWaitList(&indexAckWaitList)) { 51 | isAckWaitListFree = true; 52 | } 53 | 54 | if(isAckWaitListFree) { 55 | if(!isSubscriptionPresent(pThingName, action)) { 56 | ret_val = subscribeToShadowActionAcks(pThingName, action, isSticky); 57 | } else { 58 | incrementSubscriptionCnt(pThingName, action, isSticky); 59 | } 60 | } 61 | else { 62 | ret_val = FAILURE; 63 | } 64 | } 65 | 66 | if(SUCCESS == ret_val) { 67 | ret_val = publishToShadowAction(pThingName, action, pJsonDocumentToBeSent); 68 | } 69 | 70 | if(isClientTokenPresent && (NULL != callback) && (SUCCESS == ret_val) && isAckWaitListFree) { 71 | addToAckWaitList(indexAckWaitList, pThingName, action, extractedClientToken, callback, pCallbackContext, 72 | timeout_seconds); 73 | } 74 | 75 | FUNC_EXIT_RC(ret_val); 76 | } 77 | 78 | #ifdef __cplusplus 79 | } 80 | #endif 81 | -------------------------------------------------------------------------------- /src/timer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * Additions Copyright 2016 Espressif Systems (Shanghai) PTE LTD 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | /** 18 | * @file timer.c 19 | * @brief FreeRTOS implementation of the timer interface uses ticks. 20 | */ 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | #include 27 | 28 | #include "timer_platform.h" 29 | #include "freertos/FreeRTOS.h" 30 | #include "freertos/task.h" 31 | #include "esp_log.h" 32 | 33 | const static char *TAG = "aws_timer"; 34 | 35 | bool has_timer_expired(Timer *timer) { 36 | uint32_t now = xTaskGetTickCount(); 37 | bool expired = (now - timer->start_ticks) >= timer->timeout_ticks; 38 | 39 | /* AWS IoT SDK isn't very RTOS friendly because it polls for "done 40 | timers" a lot without ever sleeping on them. So we hack in some 41 | amount of sleeping here: if it seems like the caller is polling 42 | an unexpired timer in a tight loop then we delay a tick to let 43 | things progress elsewhere. 44 | */ 45 | if(!expired && now == timer->last_polled_ticks) { 46 | vTaskDelay(1); 47 | } 48 | timer->last_polled_ticks = now; 49 | return expired; 50 | } 51 | 52 | void countdown_ms(Timer *timer, uint32_t timeout) { 53 | timer->start_ticks = xTaskGetTickCount(); 54 | timer->timeout_ticks = timeout / portTICK_PERIOD_MS; 55 | timer->last_polled_ticks = 0; 56 | } 57 | 58 | uint32_t left_ms(Timer *timer) { 59 | uint32_t now = xTaskGetTickCount(); 60 | uint32_t elapsed = now - timer->start_ticks; 61 | if (elapsed < timer->timeout_ticks) { 62 | return (timer->timeout_ticks - elapsed) * portTICK_PERIOD_MS; 63 | } else { 64 | return 0; 65 | } 66 | } 67 | 68 | void countdown_sec(Timer *timer, uint32_t timeout) { 69 | if (timeout > UINT32_MAX / 1000) { 70 | ESP_LOGE(TAG, "timeout is out of range: %ds", timeout); 71 | } 72 | countdown_ms(timer, timeout * 1000); 73 | } 74 | 75 | void init_timer(Timer *timer) { 76 | timer->start_ticks = 0; 77 | timer->timeout_ticks = 0; 78 | timer->last_polled_ticks = 0; 79 | } 80 | 81 | #ifdef __cplusplus 82 | } 83 | #endif 84 | -------------------------------------------------------------------------------- /src/aws_iot_jobs_topics.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | /** 17 | * @file aws_iot_job_topics.h 18 | * @brief Functions for parsing and creating MQTT topics used by the AWS IoT Jobs system. 19 | */ 20 | 21 | #ifdef DISABLE_IOT_JOBS 22 | #error "Jobs API is disabled" 23 | #endif 24 | 25 | #ifndef AWS_IOT_JOBS_TOPICS_H_ 26 | #define AWS_IOT_JOBS_TOPICS_H_ 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | #define JOB_ID_NEXT "$next" 37 | #define JOB_ID_WILDCARD "+" 38 | 39 | /** 40 | * The type of job topic. 41 | */ 42 | typedef enum { 43 | JOB_UNRECOGNIZED_TOPIC = 0, 44 | JOB_GET_PENDING_TOPIC, 45 | JOB_START_NEXT_TOPIC, 46 | JOB_DESCRIBE_TOPIC, 47 | JOB_UPDATE_TOPIC, 48 | JOB_NOTIFY_TOPIC, 49 | JOB_NOTIFY_NEXT_TOPIC, 50 | JOB_WILDCARD_TOPIC 51 | } AwsIotJobExecutionTopicType; 52 | 53 | /** 54 | * The type of reply topic, or #JOB_REQUEST_TYPE for 55 | * topics that are not replies. 56 | */ 57 | typedef enum { 58 | JOB_UNRECOGNIZED_TOPIC_TYPE = 0, 59 | JOB_REQUEST_TYPE, 60 | JOB_ACCEPTED_REPLY_TYPE, 61 | JOB_REJECTED_REPLY_TYPE, 62 | JOB_WILDCARD_REPLY_TYPE 63 | } AwsIotJobExecutionTopicReplyType; 64 | 65 | /** 66 | * @brief Get the topic matching the provided details and put into the provided buffer. 67 | * 68 | * If the buffer is not large enough to store the full topic the topic will be truncated 69 | * to fit, with the last character always being a null terminator. 70 | * 71 | * \param buffer the buffer to put the results into 72 | * \param bufferSize the size of the buffer 73 | * \param topicType the type of the topic 74 | * \param replyType the reply type of the topic 75 | * \param thingName the name of the thing in the topic 76 | * \param jobId the name of the job id in the topic 77 | * \return the number of characters in the topic excluding the null terminator. A return 78 | * value of bufferSize or more means that the topic string was truncated. 79 | */ 80 | int aws_iot_jobs_get_api_topic(char *buffer, size_t bufferSize, 81 | AwsIotJobExecutionTopicType topicType, AwsIotJobExecutionTopicReplyType replyType, 82 | const char* thingName, const char* jobId); 83 | 84 | #ifdef __cplusplus 85 | } 86 | #endif 87 | 88 | #endif /* AWS_IOT_JOBS_TOPICS_H_ */ 89 | -------------------------------------------------------------------------------- /tools/Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "89313a52f5f8c30dc570017e890f487af25384a3743cc148e6148501a1d74ed9" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "2.7" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "boto3": { 20 | "hashes": [ 21 | "sha256:09b82fe8c0e5a73cb0406c137869ad2bb0d307513a4a43f993217b25bab4857a", 22 | "sha256:f3cfeadcf864730e8ac7934393eada5d398710b23e37ac66ade11fd5544acff9" 23 | ], 24 | "index": "pypi", 25 | "version": "==1.9.139" 26 | }, 27 | "botocore": { 28 | "hashes": [ 29 | "sha256:36779f02ce5e4568bb718edde9c4095d187e5f47fb840a640ddf3f33e163c80f", 30 | "sha256:abb07082f80c6a487236cb488492258df4a97365cf63e091c79f4c7b202469e5" 31 | ], 32 | "version": "==1.12.139" 33 | }, 34 | "docutils": { 35 | "hashes": [ 36 | "sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6", 37 | "sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274", 38 | "sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6" 39 | ], 40 | "version": "==0.14" 41 | }, 42 | "jmespath": { 43 | "hashes": [ 44 | "sha256:3720a4b1bd659dd2eecad0666459b9788813e032b83e7ba58578e48254e0a0e6", 45 | "sha256:bde2aef6f44302dfb30320115b17d030798de8c4110e28d5cf6cf91a7a31074c" 46 | ], 47 | "version": "==0.9.4" 48 | }, 49 | "python-dateutil": { 50 | "hashes": [ 51 | "sha256:7e6584c74aeed623791615e26efd690f29817a27c73085b78e4bad02493df2fb", 52 | "sha256:c89805f6f4d64db21ed966fda138f8a5ed7a4fdbc1a8ee329ce1b74e3c74da9e" 53 | ], 54 | "markers": "python_version >= '2.7'", 55 | "version": "==2.8.0" 56 | }, 57 | "s3transfer": { 58 | "hashes": [ 59 | "sha256:7b9ad3213bff7d357f888e0fab5101b56fa1a0548ee77d121c3a3dbfbef4cb2e", 60 | "sha256:f23d5cb7d862b104401d9021fc82e5fa0e0cf57b7660a1331425aab0c691d021" 61 | ], 62 | "version": "==0.2.0" 63 | }, 64 | "six": { 65 | "hashes": [ 66 | "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", 67 | "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" 68 | ], 69 | "version": "==1.12.0" 70 | }, 71 | "urllib3": { 72 | "hashes": [ 73 | "sha256:4c291ca23bbb55c76518905869ef34bdd5f0e46af7afe6861e8375643ffee1a0", 74 | "sha256:9a247273df709c4fedb38c711e44292304f73f39ab01beda9f6b9fc375669ac3" 75 | ], 76 | "markers": "python_version >= '3.4'", 77 | "version": "==1.24.2" 78 | } 79 | }, 80 | "develop": {} 81 | } 82 | -------------------------------------------------------------------------------- /src/aws_iot_jobs_types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | /** 17 | * @file aws_iot_jobs_types.h 18 | * @brief Structures defining the interface with the AWS IoT Jobs system 19 | * 20 | * This file defines the structures returned by and sent to the AWS IoT Jobs system. 21 | * 22 | */ 23 | 24 | #ifdef DISABLE_IOT_JOBS 25 | #error "Jobs API is disabled" 26 | #endif 27 | 28 | #ifndef AWS_IOT_JOBS_TYPES_H_ 29 | #define AWS_IOT_JOBS_TYPES_H_ 30 | 31 | #include 32 | #include 33 | #include "jsmn.h" 34 | #include "timer_interface.h" 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | typedef enum { 41 | JOB_EXECUTION_STATUS_NOT_SET = 0, 42 | JOB_EXECUTION_QUEUED, 43 | JOB_EXECUTION_IN_PROGRESS, 44 | JOB_EXECUTION_FAILED, 45 | JOB_EXECUTION_SUCCEEDED, 46 | JOB_EXECUTION_CANCELED, 47 | JOB_EXECUTION_REJECTED, 48 | /*** 49 | * Used for any status not in the supported list of statuses 50 | */ 51 | JOB_EXECUTION_UNKNOWN_STATUS = 99 52 | } JobExecutionStatus; 53 | 54 | extern const char *JOB_EXECUTION_QUEUED_STR; 55 | extern const char *JOB_EXECUTION_IN_PROGRESS_STR; 56 | extern const char *JOB_EXECUTION_FAILED_STR; 57 | extern const char *JOB_EXECUTION_SUCCESS_STR; 58 | extern const char *JOB_EXECUTION_CANCELED_STR; 59 | extern const char *JOB_EXECUTION_REJECTED_STR; 60 | 61 | /** 62 | * Convert a string to its matching status. 63 | * 64 | * \return the matching status, or JOB_EXECUTION_UNKNOWN_STATUS if the string was not recognized. 65 | */ 66 | JobExecutionStatus aws_iot_jobs_map_string_to_job_status(const char *str); 67 | 68 | /** 69 | * Convert a status to its string. 70 | * 71 | * \return a string representing the status, or null if the status is not recognized. 72 | */ 73 | const char *aws_iot_jobs_map_status_to_string(JobExecutionStatus status); 74 | 75 | /** 76 | * A request to update the status of a job execution. 77 | */ 78 | typedef struct { 79 | int64_t expectedVersion; // set to 0 to ignore 80 | int64_t executionNumber; // set to 0 to ignore 81 | JobExecutionStatus status; 82 | const char *statusDetails; 83 | bool includeJobExecutionState; 84 | bool includeJobDocument; 85 | const char *clientToken; 86 | } AwsIotJobExecutionUpdateRequest; 87 | 88 | /** 89 | * A request to get the status of a job execution. 90 | */ 91 | typedef struct { 92 | int64_t executionNumber; // set to 0 to ignore 93 | bool includeJobDocument; 94 | const char *clientToken; 95 | } AwsIotDescribeJobExecutionRequest; 96 | 97 | /** 98 | * A request to get and start the next pending (not in a terminal state) job execution for a Thing. 99 | */ 100 | typedef struct { 101 | const char *statusDetails; 102 | const char *clientToken; 103 | } AwsIotStartNextPendingJobExecutionRequest; 104 | 105 | #ifdef __cplusplus 106 | } 107 | #endif 108 | 109 | #endif /* AWS_IOT_JOBS_TYPES_H_ */ 110 | -------------------------------------------------------------------------------- /src/threads_freertos.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * Additions Copyright 2016 Espressif Systems (Shanghai) PTE LTD 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"). 6 | * You may not use this file except in compliance with the License. 7 | * A copy of the License is located at 8 | * 9 | * http://aws.amazon.com/apache2.0 10 | * 11 | * or in the "license" file accompanying this file. This file is distributed 12 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 | * express or implied. See the License for the specific language governing 14 | * permissions and limitations under the License. 15 | */ 16 | 17 | 18 | #include "freertos/FreeRTOS.h" 19 | #include "freertos/task.h" 20 | 21 | #include "threads_platform.h" 22 | 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif 26 | 27 | /** 28 | * @brief Initialize the provided mutex 29 | * 30 | * Call this function to initialize the mutex 31 | * 32 | * @param IoT_Mutex_t - pointer to the mutex to be initialized 33 | * @return IoT_Error_t - error code indicating result of operation 34 | */ 35 | IoT_Error_t aws_iot_thread_mutex_init(IoT_Mutex_t *pMutex) { 36 | 37 | pMutex->mutex = xSemaphoreCreateRecursiveMutex(); 38 | return pMutex->mutex ? SUCCESS : MUTEX_INIT_ERROR; 39 | } 40 | 41 | /** 42 | * @brief Lock the provided mutex 43 | * 44 | * Call this function to lock the mutex before performing a state change 45 | * Blocking, thread will block until lock request fails 46 | * 47 | * @param IoT_Mutex_t - pointer to the mutex to be locked 48 | * @return IoT_Error_t - error code indicating result of operation 49 | */ 50 | IoT_Error_t aws_iot_thread_mutex_lock(IoT_Mutex_t *pMutex) { 51 | xSemaphoreTakeRecursive(pMutex->mutex, portMAX_DELAY); 52 | return SUCCESS; 53 | } 54 | 55 | /** 56 | * @brief Try to lock the provided mutex 57 | * 58 | * Call this function to attempt to lock the mutex before performing a state change 59 | * Non-Blocking, immediately returns with failure if lock attempt fails 60 | * 61 | * @param IoT_Mutex_t - pointer to the mutex to be locked 62 | * @return IoT_Error_t - error code indicating result of operation 63 | */ 64 | IoT_Error_t aws_iot_thread_mutex_trylock(IoT_Mutex_t *pMutex) { 65 | if (xSemaphoreTakeRecursive(pMutex->mutex, 0)) { 66 | return SUCCESS; 67 | } else { 68 | return MUTEX_LOCK_ERROR; 69 | } 70 | } 71 | 72 | /** 73 | * @brief Unlock the provided mutex 74 | * 75 | * Call this function to unlock the mutex before performing a state change 76 | * 77 | * @param IoT_Mutex_t - pointer to the mutex to be unlocked 78 | * @return IoT_Error_t - error code indicating result of operation 79 | */ 80 | IoT_Error_t aws_iot_thread_mutex_unlock(IoT_Mutex_t *pMutex) { 81 | if (xSemaphoreGiveRecursive(pMutex->mutex)) { 82 | return SUCCESS; 83 | } else { 84 | return MUTEX_UNLOCK_ERROR; 85 | } 86 | } 87 | 88 | /** 89 | * @brief Destroy the provided mutex 90 | * 91 | * Call this function to destroy the mutex 92 | * 93 | * @param IoT_Mutex_t - pointer to the mutex to be destroyed 94 | * @return IoT_Error_t - error code indicating result of operation 95 | */ 96 | IoT_Error_t aws_iot_thread_mutex_destroy(IoT_Mutex_t *pMutex) { 97 | vSemaphoreDelete(pMutex->mutex); 98 | return SUCCESS; 99 | } 100 | 101 | #ifdef __cplusplus 102 | } 103 | #endif 104 | 105 | -------------------------------------------------------------------------------- /src/timer_interface.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014 IBM Corp. 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * and Eclipse Distribution License v1.0 which accompany this distribution. 7 | * 8 | * The Eclipse Public License is available at 9 | * http://www.eclipse.org/legal/epl-v10.html 10 | * and the Eclipse Distribution License is available at 11 | * http://www.eclipse.org/org/documents/edl-v10.php. 12 | * 13 | * Contributors: 14 | * Allan Stockdill-Mander - initial API and implementation and/or initial documentation 15 | *******************************************************************************/ 16 | 17 | /** 18 | * @file timer_interface.h 19 | * @brief Timer interface definition for MQTT client. 20 | * 21 | * Defines an interface to timers that can be used by other system 22 | * components. MQTT client requires timers to handle timeouts and 23 | * MQTT keep alive. 24 | * Starting point for porting the SDK to the timer hardware layer of a new platform. 25 | */ 26 | 27 | #ifndef __TIMER_INTERFACE_H_ 28 | #define __TIMER_INTERFACE_H_ 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif 33 | 34 | /** 35 | * The platform specific timer header that defines the Timer struct 36 | */ 37 | #include "timer_platform.h" 38 | 39 | #include 40 | #include 41 | 42 | /** 43 | * @brief Timer Type 44 | * 45 | * Forward declaration of a timer struct. The definition of this struct is 46 | * platform dependent. When porting to a new platform add this definition 47 | * in "timer_.h" and include that file above. 48 | * 49 | */ 50 | typedef struct Timer Timer; 51 | 52 | /** 53 | * @brief Check if a timer is expired 54 | * 55 | * Call this function passing in a timer to check if that timer has expired. 56 | * 57 | * @param Timer - pointer to the timer to be checked for expiration 58 | * @return bool - true = timer expired, false = timer not expired 59 | */ 60 | bool has_timer_expired(Timer *); 61 | 62 | /** 63 | * @brief Create a timer (milliseconds) 64 | * 65 | * Sets the timer to expire in a specified number of milliseconds. 66 | * 67 | * @param Timer - pointer to the timer to be set to expire in milliseconds 68 | * @param uint32_t - set the timer to expire in this number of milliseconds 69 | */ 70 | void countdown_ms(Timer *, uint32_t); 71 | 72 | /** 73 | * @brief Create a timer (seconds) 74 | * 75 | * Sets the timer to expire in a specified number of seconds. 76 | * 77 | * @param Timer - pointer to the timer to be set to expire in seconds 78 | * @param uint32_t - set the timer to expire in this number of seconds 79 | */ 80 | void countdown_sec(Timer *, uint32_t); 81 | 82 | /** 83 | * @brief Check the time remaining on a given timer 84 | * 85 | * Checks the input timer and returns the number of milliseconds remaining on the timer. 86 | * 87 | * @param Timer - pointer to the timer to be set to checked 88 | * @return int - milliseconds left on the countdown timer 89 | */ 90 | uint32_t left_ms(Timer *); 91 | 92 | /** 93 | * @brief Initialize a timer 94 | * 95 | * Performs any initialization required to the timer passed in. 96 | * 97 | * @param Timer - pointer to the timer to be initialized 98 | */ 99 | void init_timer(Timer *); 100 | 101 | #ifdef __cplusplus 102 | } 103 | #endif 104 | 105 | #endif //__TIMER_INTERFACE_H_ 106 | -------------------------------------------------------------------------------- /src/threads_interface.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | /** 17 | * @file threads_interface.h 18 | * @brief Thread interface definition for MQTT client. 19 | * 20 | * Defines an interface that can be used by system components for multithreaded situations. 21 | * Starting point for porting the SDK to the threading hardware layer of a new platform. 22 | */ 23 | 24 | #include "aws_iot_config.h" 25 | 26 | #ifdef _ENABLE_THREAD_SUPPORT_ 27 | #ifndef __THREADS_INTERFACE_H_ 28 | #define __THREADS_INTERFACE_H_ 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif 33 | 34 | /** 35 | * The platform specific timer header that defines the Timer struct 36 | */ 37 | #include "threads_platform.h" 38 | 39 | #include 40 | 41 | /** 42 | * @brief Mutex Type 43 | * 44 | * Forward declaration of a mutex struct. The definition of this struct is 45 | * platform dependent. When porting to a new platform add this definition 46 | * in "threads_platform.h". 47 | * 48 | */ 49 | typedef struct _IoT_Mutex_t IoT_Mutex_t; 50 | 51 | /** 52 | * @brief Initialize the provided mutex 53 | * 54 | * Call this function to initialize the mutex 55 | * 56 | * @param IoT_Mutex_t - pointer to the mutex to be initialized 57 | * @return IoT_Error_t - error code indicating result of operation 58 | */ 59 | IoT_Error_t aws_iot_thread_mutex_init(IoT_Mutex_t *); 60 | 61 | /** 62 | * @brief Lock the provided mutex 63 | * 64 | * Call this function to lock the mutex before performing a state change 65 | * This is a blocking call. 66 | * 67 | * @param IoT_Mutex_t - pointer to the mutex to be locked 68 | * @return IoT_Error_t - error code indicating result of operation 69 | */ 70 | IoT_Error_t aws_iot_thread_mutex_lock(IoT_Mutex_t *); 71 | 72 | /** 73 | * @brief Lock the provided mutex 74 | * 75 | * Call this function to lock the mutex before performing a state change. 76 | * This is not a blocking call. 77 | * 78 | * @param IoT_Mutex_t - pointer to the mutex to be locked 79 | * @return IoT_Error_t - error code indicating result of operation 80 | */ 81 | IoT_Error_t aws_iot_thread_mutex_trylock(IoT_Mutex_t *); 82 | 83 | /** 84 | * @brief Unlock the provided mutex 85 | * 86 | * Call this function to unlock the mutex before performing a state change 87 | * 88 | * @param IoT_Mutex_t - pointer to the mutex to be unlocked 89 | * @return IoT_Error_t - error code indicating result of operation 90 | */ 91 | IoT_Error_t aws_iot_thread_mutex_unlock(IoT_Mutex_t *); 92 | 93 | /** 94 | * @brief Destroy the provided mutex 95 | * 96 | * Call this function to destroy the mutex 97 | * 98 | * @param IoT_Mutex_t - pointer to the mutex to be destroyed 99 | * @return IoT_Error_t - error code indicating result of operation 100 | */ 101 | IoT_Error_t aws_iot_thread_mutex_destroy(IoT_Mutex_t *); 102 | 103 | #ifdef __cplusplus 104 | } 105 | #endif 106 | 107 | #endif /*__THREADS_INTERFACE_H_*/ 108 | #endif /*_ENABLE_THREAD_SUPPORT_*/ 109 | -------------------------------------------------------------------------------- /tools/create_thing/create_thing/create_thing.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | use boto to create a thing, attach a policy, attach a certificate and provide 4 | the private key and certificate as pastable c++ source. 5 | 6 | usage: create_thing.py [-h] [--type-name TYPE_NAME] name policy-name 7 | 8 | positional arguments: 9 | name name of the thing to create 10 | policy-name policy to attach thing to 11 | 12 | optional arguments: 13 | -h, --help show this help message and exit 14 | --type-name TYPE_NAME 15 | thing type name 16 | 17 | (C) Copyright 2019-2020 Jan Delgado 18 | """ 19 | import sys 20 | import argparse 21 | import boto3 22 | 23 | 24 | def string_as_c_literal(s): 25 | """return string s as a c multi-line string literal""" 26 | return "\n".join([ f"\"{l}\\n\"" for l in s.split("\n") ]) 27 | 28 | def print_key_and_cert(f, cert, thing_name): 29 | """print key and certificate as c++ source ready to be included in a client sketch """ 30 | 31 | print(""" 32 | // ------------------------------------------------------------------------- 33 | // certificateArn: {arn} 34 | // for thing: {thing_name} 35 | // DO NOT PUT THIS FILE UNDER SOURCE CONTROL. 36 | // ------------------------------------------------------------------------- 37 | auto constexpr certificate_pem_crt = {cert}; 38 | 39 | auto constexpr private_pem_key= {key}; 40 | 41 | """.format(arn=cert['certificateArn'], 42 | thing_name=thing_name, 43 | cert=string_as_c_literal(cert['certificatePem']), 44 | key=string_as_c_literal(cert['keyPair']['PrivateKey']), 45 | file=f)) 46 | 47 | 48 | def create_thing(iot, thing_name, thing_type_name=None): 49 | kwargs = {'thingName': thing_name} 50 | if thing_type_name: 51 | kwargs['thingTypeName'] = thing_type_name 52 | return iot.create_thing(**kwargs) 53 | 54 | 55 | def create_keys_and_certificate(iot): 56 | return iot.create_keys_and_certificate(setAsActive=True) 57 | 58 | 59 | def attach_thing_principal(iot, thing_name, principal_arn): 60 | return iot.attach_thing_principal(thingName=thing_name, 61 | principal=principal_arn) 62 | 63 | 64 | def attach_policy(iot, thing_arn, policy_name): 65 | return iot.attach_policy(policyName=policy_name, target=thing_arn) 66 | 67 | 68 | def create_cli_parser(): 69 | parser = argparse.ArgumentParser() 70 | parser.add_argument("name", type=str, help="name of the thing to create") 71 | parser.add_argument("policy_name", 72 | type=str, 73 | help="policy to attach thing to") 74 | parser.add_argument("--type-name", type=str, help="thing type name") 75 | return parser 76 | 77 | 78 | def main(argv): 79 | parser = create_cli_parser() 80 | args = parser.parse_args() 81 | 82 | iot = boto3.client('iot') 83 | 84 | thing = create_thing(iot, args.name, args.type_name) 85 | cert = create_keys_and_certificate(iot) 86 | attach_thing_principal(iot, args.name, cert['certificateArn']) 87 | attach_policy(iot, cert['certificateArn'], args.policy_name) 88 | 89 | print("created thing {}".format(thing['thingArn']), file=sys.stderr) 90 | print("attached certificate {}".format(cert['certificateArn']), 91 | file=sys.stderr) 92 | 93 | print_key_and_cert(sys.stdout, cert, args.name) 94 | 95 | 96 | def run(): 97 | main(sys.argv) 98 | 99 | if __name__ == '__main__': 100 | run() 101 | 102 | -------------------------------------------------------------------------------- /src/aws_iot_log.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | /** 17 | * @file aws_iot_log.h 18 | * @brief Logging macros for the SDK. 19 | * This file defines common logging macros with log levels to be used within the SDK. 20 | * These macros can also be used in the IoT application code as a common way to output 21 | * logs. The log levels can be tuned by modifying the makefile. Removing (commenting 22 | * out) the IOT_* statement in the makefile disables that log level. 23 | * 24 | * It is expected that the macros below will be modified or replaced when porting to 25 | * specific hardware platforms as printf may not be the desired behavior. 26 | */ 27 | 28 | #ifndef _IOT_LOG_H 29 | #define _IOT_LOG_H 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | #include 36 | #include 37 | 38 | /** 39 | * @brief Debug level logging macro. 40 | * 41 | * Macro to expose function, line number as well as desired log message. 42 | */ 43 | #ifdef ENABLE_IOT_DEBUG 44 | #define IOT_DEBUG(...) \ 45 | {\ 46 | printf("DEBUG: %s L#%d ", __func__, __LINE__); \ 47 | printf(__VA_ARGS__); \ 48 | printf("\n"); \ 49 | } 50 | #else 51 | #define IOT_DEBUG(...) 52 | #endif 53 | 54 | /** 55 | * @brief Debug level trace logging macro. 56 | * 57 | * Macro to print message function entry and exit 58 | */ 59 | #ifdef ENABLE_IOT_TRACE 60 | #define FUNC_ENTRY \ 61 | {\ 62 | printf("FUNC_ENTRY: %s L#%d \n", __func__, __LINE__); \ 63 | } 64 | #define FUNC_EXIT \ 65 | {\ 66 | printf("FUNC_EXIT: %s L#%d \n", __func__, __LINE__); \ 67 | } 68 | #define FUNC_EXIT_RC(x) \ 69 | {\ 70 | printf("FUNC_EXIT: %s L#%d Return Code : %d \n", __func__, __LINE__, x); \ 71 | return x; \ 72 | } 73 | #else 74 | #define FUNC_ENTRY 75 | 76 | #define FUNC_EXIT 77 | #define FUNC_EXIT_RC(x) { return x; } 78 | #endif 79 | 80 | /** 81 | * @brief Info level logging macro. 82 | * 83 | * Macro to expose desired log message. Info messages do not include automatic function names and line numbers. 84 | */ 85 | #ifdef ENABLE_IOT_INFO 86 | #define IOT_INFO(...) \ 87 | {\ 88 | printf(__VA_ARGS__); \ 89 | printf("\n"); \ 90 | } 91 | #else 92 | #define IOT_INFO(...) 93 | #endif 94 | 95 | /** 96 | * @brief Warn level logging macro. 97 | * 98 | * Macro to expose function, line number as well as desired log message. 99 | */ 100 | #ifdef ENABLE_IOT_WARN 101 | #define IOT_WARN(...) \ 102 | { \ 103 | printf("WARN: %s L#%d ", __func__, __LINE__); \ 104 | printf(__VA_ARGS__); \ 105 | printf("\n"); \ 106 | } 107 | #else 108 | #define IOT_WARN(...) 109 | #endif 110 | 111 | /** 112 | * @brief Error level logging macro. 113 | * 114 | * Macro to expose function, line number as well as desired log message. 115 | */ 116 | #ifdef ENABLE_IOT_ERROR 117 | #define IOT_ERROR(...) \ 118 | { \ 119 | printf("ERROR: %s L#%d ", __func__, __LINE__); \ 120 | printf(__VA_ARGS__); \ 121 | printf("\n"); \ 122 | } 123 | #else 124 | #define IOT_ERROR(...) 125 | #endif 126 | 127 | #ifdef __cplusplus 128 | } 129 | #endif 130 | 131 | #endif // _IOT_LOG_H 132 | -------------------------------------------------------------------------------- /src/aws_iot_jobs_topics.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | #include "aws_iot_jobs_topics.h" 21 | #include 22 | #include 23 | #include 24 | 25 | #define BASE_THINGS_TOPIC "$aws/things/" 26 | 27 | #define NOTIFY_OPERATION "notify" 28 | #define NOTIFY_NEXT_OPERATION "notify-next" 29 | #define GET_OPERATION "get" 30 | #define START_NEXT_OPERATION "start-next" 31 | #define WILDCARD_OPERATION "+" 32 | #define UPDATE_OPERATION "update" 33 | #define ACCEPTED_REPLY "accepted" 34 | #define REJECTED_REPLY "rejected" 35 | #define WILDCARD_REPLY "+" 36 | 37 | static const char *_get_operation_for_base_topic(AwsIotJobExecutionTopicType topicType) { 38 | switch (topicType) { 39 | case JOB_UPDATE_TOPIC: 40 | return UPDATE_OPERATION; 41 | case JOB_NOTIFY_TOPIC: 42 | return NOTIFY_OPERATION; 43 | case JOB_NOTIFY_NEXT_TOPIC: 44 | return NOTIFY_NEXT_OPERATION; 45 | case JOB_GET_PENDING_TOPIC: 46 | case JOB_DESCRIBE_TOPIC: 47 | return GET_OPERATION; 48 | case JOB_START_NEXT_TOPIC: 49 | return START_NEXT_OPERATION; 50 | case JOB_WILDCARD_TOPIC: 51 | return WILDCARD_OPERATION; 52 | case JOB_UNRECOGNIZED_TOPIC: 53 | default: 54 | return NULL; 55 | } 56 | } 57 | 58 | static bool _base_topic_requires_job_id(AwsIotJobExecutionTopicType topicType) { 59 | switch (topicType) { 60 | case JOB_UPDATE_TOPIC: 61 | case JOB_DESCRIBE_TOPIC: 62 | return true; 63 | case JOB_NOTIFY_TOPIC: 64 | case JOB_NOTIFY_NEXT_TOPIC: 65 | case JOB_START_NEXT_TOPIC: 66 | case JOB_GET_PENDING_TOPIC: 67 | case JOB_WILDCARD_TOPIC: 68 | case JOB_UNRECOGNIZED_TOPIC: 69 | default: 70 | return false; 71 | } 72 | } 73 | 74 | static const char *_get_suffix_for_topic_type(AwsIotJobExecutionTopicReplyType replyType) { 75 | switch (replyType) { 76 | case JOB_REQUEST_TYPE: 77 | return ""; 78 | break; 79 | case JOB_ACCEPTED_REPLY_TYPE: 80 | return "/" ACCEPTED_REPLY; 81 | break; 82 | case JOB_REJECTED_REPLY_TYPE: 83 | return "/" REJECTED_REPLY; 84 | break; 85 | case JOB_WILDCARD_REPLY_TYPE: 86 | return "/" WILDCARD_REPLY; 87 | break; 88 | case JOB_UNRECOGNIZED_TOPIC_TYPE: 89 | default: 90 | return NULL; 91 | } 92 | } 93 | 94 | int aws_iot_jobs_get_api_topic(char *buffer, size_t bufferSize, 95 | AwsIotJobExecutionTopicType topicType, AwsIotJobExecutionTopicReplyType replyType, 96 | const char* thingName, const char* jobId) 97 | { 98 | if (thingName == NULL) { 99 | return -1; 100 | } 101 | 102 | if ((topicType == JOB_NOTIFY_TOPIC || topicType == JOB_NOTIFY_NEXT_TOPIC) && replyType != JOB_REQUEST_TYPE) { 103 | return -1; 104 | } 105 | 106 | bool requireJobId = _base_topic_requires_job_id(topicType); 107 | if (jobId == NULL && requireJobId) { 108 | return -1; 109 | } 110 | 111 | const char *operation = _get_operation_for_base_topic(topicType); 112 | if (operation == NULL) { 113 | return -1; 114 | } 115 | 116 | const char *suffix = _get_suffix_for_topic_type(replyType); 117 | 118 | if (requireJobId || (topicType == JOB_WILDCARD_TOPIC && jobId != NULL)) { 119 | return snprintf(buffer, bufferSize, BASE_THINGS_TOPIC "%s/jobs/%s/%s%s", thingName, jobId, operation, suffix); 120 | } else if (topicType == JOB_WILDCARD_TOPIC) { 121 | return snprintf(buffer, bufferSize, BASE_THINGS_TOPIC "%s/jobs/#", thingName); 122 | } else { 123 | return snprintf(buffer, bufferSize, BASE_THINGS_TOPIC "%s/jobs/%s%s", thingName, operation, suffix); 124 | } 125 | } 126 | 127 | #ifdef __cplusplus 128 | } 129 | #endif 130 | -------------------------------------------------------------------------------- /examples/pubSubTest/config.h-dist: -------------------------------------------------------------------------------- 1 | #ifndef _CONFIG_H_ 2 | #define _CONFIG_H_ 3 | 4 | // TODO ADD YOUR CONFIGURATION HERE 5 | 6 | // WiFi and MQTT configuration 7 | static auto constexpr WIFI_SSID = "YOUR_SSID"; 8 | static auto constexpr WIFI_PASSWORD = "YOUR_PASSWORD"; 9 | 10 | // DHCP client id 11 | static auto constexpr CLIENT_ID = "CLIENTID"; 12 | 13 | // hostname of your MQTT ATS endpoint 14 | static auto constexpr HOST_ADDRESS = "DNS_OF_YOUR_MQTT_ENDPOINT"; 15 | static auto constexpr TOPIC_NAME = "some/topic"; 16 | 17 | // "AWS root CA1 and CA2 (RSA)", see 18 | // https://docs.aws.amazon.com/iot/latest/developerguide/managing-device-certs.html#server-authentication 19 | static auto constexpr aws_root_ca_pem = "-----BEGIN CERTIFICATE-----\n\ 20 | MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF\ 21 | ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6\ 22 | b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL\ 23 | MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv\ 24 | b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj\ 25 | ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM\ 26 | 9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw\ 27 | IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6\ 28 | VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L\ 29 | 93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm\ 30 | jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\ 31 | AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA\ 32 | A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI\ 33 | U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs\ 34 | N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv\ 35 | o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU\ 36 | 5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy\ 37 | rqXRfboQnoZsG4q5WTP468SQvvG5\ 38 | -----END CERTIFICATE-----\ 39 | -----BEGIN CERTIFICATE-----\ 40 | MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF\ 41 | ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6\ 42 | b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL\ 43 | MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv\ 44 | b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK\ 45 | gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ\ 46 | W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg\ 47 | 1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K\ 48 | 8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r\ 49 | 2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me\ 50 | z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR\ 51 | 8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj\ 52 | mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz\ 53 | 7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6\ 54 | +XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI\ 55 | 0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB\ 56 | Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm\ 57 | UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2\ 58 | LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY\ 59 | +gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS\ 60 | k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl\ 61 | 7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm\ 62 | btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl\ 63 | urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+\ 64 | fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63\ 65 | n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE\ 66 | 76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H\ 67 | 9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT\ 68 | 4PsJYGw=\ 69 | -----END CERTIFICATE-----\n"; 70 | 71 | 72 | // certificate and private key for the thing. See README.md for details 73 | // and use the create_thing.py script to create certificate and key. 74 | 75 | // "The certificate for this thing" 76 | auto constexpr certificate_pem_crt = "-----BEGIN CERTIFICATE-----\n" 77 | "...\n" 78 | "-----END CERTIFICATE-----\n"; 79 | 80 | // "The private key of the thing". The public key is not needed here. 81 | auto constexpr private_pem_key = "-----BEGIN RSA PRIVATE KEY-----\n" 82 | "...\n" 83 | "-----END RSA PRIVATE KEY-----\n"; 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /src/aws_iot_jobs_json.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | /** 17 | * @file aws_iot_jobs_json.h 18 | * @brief Functions for mapping between json and the AWS Iot Job data structures. 19 | */ 20 | 21 | #ifdef DISABLE_IOT_JOBS 22 | #error "Jobs API is disabled" 23 | #endif 24 | 25 | #ifndef AWS_IOT_JOBS_JSON_H_ 26 | #define AWS_IOT_JOBS_JSON_H_ 27 | 28 | #include 29 | #include "jsmn.h" 30 | #include "aws_iot_jobs_types.h" 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | /** 37 | * Serialize a job execution update request into a json string. 38 | * 39 | * \param requestBuffer buffer to contain the serialized request. If null 40 | * this function will return the size of the buffer required 41 | * \param bufferSize the size of the buffer. If this is smaller than the required 42 | * length the string will be truncated to fit. 43 | * \request the request to serialize. 44 | * \return The size of the json string to store the serialized request or -1 45 | * if the request is invalid. Note that the return value should be checked against 46 | * the size of the buffer and if its larger handle the fact that the string has 47 | * been truncated. 48 | */ 49 | int aws_iot_jobs_json_serialize_update_job_execution_request( 50 | char *requestBuffer, size_t bufferSize, 51 | const AwsIotJobExecutionUpdateRequest *request); 52 | 53 | /** 54 | * Serialize a job API request that contains only a client token. 55 | * 56 | * \param requestBuffer buffer to contain the serialized request. If null 57 | * this function will return the size of the buffer required 58 | * \param bufferSize the size of the buffer. If this is smaller than the required 59 | * length the string will be truncated to fit. 60 | * \param clientToken the client token to use for the request. 61 | * \return The size of the json string to store the serialized request or -1 62 | * if the request is invalid. Note that the return value should be checked against 63 | * the size of the buffer and if its larger handle the fact that the string has 64 | * been truncated. 65 | */ 66 | int aws_iot_jobs_json_serialize_client_token_only_request( 67 | char *requestBuffer, size_t bufferSize, 68 | const char *clientToken); 69 | 70 | /** 71 | * Serialize describe job execution request into json string. 72 | * 73 | * \param requestBuffer buffer to contain the serialized request. If null 74 | * this function will return the size of the buffer required 75 | * \param bufferSize the size of the buffer. If this is smaller than the required 76 | * length the string will be truncated to fit. 77 | * \param request the request to serialize. 78 | * \return The size of the json string to store the serialized request or -1 79 | * if the request is invalid. Note that the return value should be checked against 80 | * the size of the buffer and if its larger handle the fact that the string has 81 | * been truncated. 82 | */ 83 | int aws_iot_jobs_json_serialize_describe_job_execution_request( 84 | char *requestBuffer, size_t bufferSize, 85 | const AwsIotDescribeJobExecutionRequest *request); 86 | 87 | /** 88 | * Serialize start next job execution request into json string. 89 | * 90 | * \param requestBuffer buffer to contain the serialized request. If null 91 | * this function will return the size of the buffer required 92 | * \param bufferSize the size of the buffer. If this is smaller than the required 93 | * length the string will be truncated to fit. 94 | * \param request the start-next request to serialize. 95 | * \return The size of the json string to store the serialized request or -1 96 | * if the request is invalid. Note that the return value should be checked against 97 | * the size of the buffer and if its larger handle the fact that the string has 98 | * been truncated. 99 | */ 100 | int aws_iot_jobs_json_serialize_start_next_job_execution_request( 101 | char *requestBuffer, size_t bufferSize, 102 | const AwsIotStartNextPendingJobExecutionRequest *request); 103 | 104 | #ifdef __cplusplus 105 | } 106 | #endif 107 | 108 | #endif /* AWS_IOT_JOBS_JSON_H_ */ 109 | -------------------------------------------------------------------------------- /src/aws_iot_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | /** 17 | * @file aws_iot_config.h 18 | * @brief AWS IoT specific configuration file 19 | */ 20 | 21 | #ifndef _AWS_IOT_CONFIG_H__ 22 | #define _AWS_IOT_CONFIG_H__ 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | #include "aws_iot_log.h" 29 | 30 | 31 | extern char AWS_IOT_HOST_ADDRESS[]; 32 | 33 | 34 | #define CONFIG_AWS_IOT_MQTT_HOST AWS_IOT_HOST_ADDRESS 35 | #define CONFIG_AWS_IOT_MQTT_PORT 8883 36 | 37 | 38 | // This configuration macro needs to be available globally to enable threading 39 | #define _ENABLE_THREAD_SUPPORT_ 40 | 41 | // These values are defined in the menuconfig of the AWS IoT component. 42 | // However, you can override these constants from your own code. 43 | #define AWS_IOT_MQTT_HOST CONFIG_AWS_IOT_MQTT_HOST ///< Customer specific MQTT HOST. The same will be used for Thing Shadow 44 | #define AWS_IOT_MQTT_PORT CONFIG_AWS_IOT_MQTT_PORT ///< default port for MQTT/S 45 | 46 | // These values are defaults and are used for ShadowConnectParametersDefault. 47 | // You should override them from your own code. 48 | #define AWS_IOT_MQTT_CLIENT_ID "ESP32" ///< MQTT client ID should be unique for every device 49 | #define AWS_IOT_MY_THING_NAME "ESP32" ///< Thing Name of the Shadow this device is associated with 50 | 51 | // MQTT PubSub 52 | #define AWS_IOT_MQTT_TX_BUF_LEN 512 ///< Any time a message is sent out through the MQTT layer. The message is copied into this buffer anytime a publish is done. This will also be used in the case of Thing Shadow 53 | #define AWS_IOT_MQTT_RX_BUF_LEN 512 ///< Any message that comes into the device should be less than this buffer size. If a received message is bigger than this buffer size the message will be dropped. 54 | #define AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS 5 ///< Maximum number of topic filters the MQTT client can handle at any given time. This should be increased appropriately when using Thing Shadow 55 | 56 | // Thing Shadow specific configs 57 | #define SHADOW_MAX_SIZE_OF_RX_BUFFER (AWS_IOT_MQTT_RX_BUF_LEN + 1) ///< Maximum size of the SHADOW buffer to store the received Shadow message 58 | #define MAX_SIZE_OF_UNIQUE_CLIENT_ID_BYTES 80 ///< Maximum size of the Unique Client Id. For More info on the Client Id refer \ref response "Acknowledgments" 59 | #define MAX_SIZE_CLIENT_ID_WITH_SEQUENCE (MAX_SIZE_OF_UNIQUE_CLIENT_ID_BYTES + 10) ///< This is size of the extra sequence number that will be appended to the Unique client Id 60 | #define MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE (MAX_SIZE_CLIENT_ID_WITH_SEQUENCE + 20) ///< This is size of the the total clientToken key and value pair in the JSON 61 | #define MAX_ACKS_TO_COMEIN_AT_ANY_GIVEN_TIME 10 ///< At Any given time we will wait for this many responses. This will correlate to the rate at which the shadow actions are requested 62 | #define MAX_THINGNAME_HANDLED_AT_ANY_GIVEN_TIME 10 ///< We could perform shadow action on any thing Name and this is maximum Thing Names we can act on at any given time 63 | #define MAX_JSON_TOKEN_EXPECTED 120 ///< These are the max tokens that is expected to be in the Shadow JSON document. Include the metadata that gets published 64 | #define MAX_SHADOW_TOPIC_LENGTH_WITHOUT_THINGNAME 60 ///< All shadow actions have to be published or subscribed to a topic which is of the formablogt $aws/things/{thingName}/shadow/update/accepted. This refers to the size of the topic without the Thing Name 65 | #define MAX_SIZE_OF_THING_NAME 20 ///< The Thing Name should not be bigger than this value. Modify this if the Thing Name needs to be bigger 66 | #define MAX_SHADOW_TOPIC_LENGTH_BYTES (MAX_SHADOW_TOPIC_LENGTH_WITHOUT_THINGNAME + MAX_SIZE_OF_THING_NAME) ///< This size includes the length of topic with Thing Name 67 | 68 | // Auto Reconnect specific config 69 | #define AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL 1000 ///< Minimum time before the First reconnect attempt is made as part of the exponential back-off algorithm 70 | #define AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL 128000 ///< Maximum time interval after which exponential back-off will stop attempting to reconnect. 71 | 72 | #ifdef __cplusplus 73 | } 74 | #endif 75 | 76 | #endif /* _AWS_IOT_CONFIG_H_ */ 77 | -------------------------------------------------------------------------------- /src/aws_iot_mqtt_client_common_internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | // Based on Eclipse Paho. 17 | /******************************************************************************* 18 | * Copyright (c) 2014 IBM Corp. 19 | * 20 | * All rights reserved. This program and the accompanying materials 21 | * are made available under the terms of the Eclipse Public License v1.0 22 | * and Eclipse Distribution License v1.0 which accompany this distribution. 23 | * 24 | * The Eclipse Public License is available at 25 | * http://www.eclipse.org/legal/epl-v10.html 26 | * and the Eclipse Distribution License is available at 27 | * http://www.eclipse.org/org/documents/edl-v10.php. 28 | * 29 | * Contributors: 30 | * Ian Craggs - initial API and implementation and/or initial documentation 31 | * Xiang Rong - 442039 Add makefile to Embedded C client 32 | *******************************************************************************/ 33 | 34 | /** 35 | * @file aws_iot_mqtt_client_common_internal.h 36 | * @brief Internal MQTT functions not exposed to application 37 | */ 38 | 39 | #ifndef AWS_IOT_SDK_SRC_IOT_COMMON_INTERNAL_H 40 | #define AWS_IOT_SDK_SRC_IOT_COMMON_INTERNAL_H 41 | 42 | #ifdef __cplusplus 43 | extern "C" { 44 | #endif 45 | 46 | #include 47 | #include 48 | #include 49 | 50 | #include "aws_iot_log.h" 51 | #include "aws_iot_mqtt_client_interface.h" 52 | 53 | /* Enum order should match the packet ids array defined in MQTTFormat.c */ 54 | typedef enum msgTypes { 55 | UNKNOWN = -1, 56 | CONNECT = 1, 57 | CONNACK = 2, 58 | PUBLISH = 3, 59 | PUBACK = 4, 60 | PUBREC = 5, 61 | PUBREL = 6, 62 | PUBCOMP = 7, 63 | SUBSCRIBE = 8, 64 | SUBACK = 9, 65 | UNSUBSCRIBE = 10, 66 | UNSUBACK = 11, 67 | PINGREQ = 12, 68 | PINGRESP = 13, 69 | DISCONNECT = 14 70 | } MessageTypes; 71 | 72 | /* Macros for parsing header fields from incoming MQTT frame. */ 73 | #define MQTT_HEADER_FIELD_TYPE(_byte) ((_byte >> 4) & 0x0F) 74 | #define MQTT_HEADER_FIELD_DUP(_byte) ((_byte & (1 << 3)) >> 3) 75 | #define MQTT_HEADER_FIELD_QOS(_byte) ((_byte & (3 << 1)) >> 1) 76 | #define MQTT_HEADER_FIELD_RETAIN(_byte) ((_byte & (1 << 0)) >> 0) 77 | 78 | /** 79 | * Bitfields for the MQTT header byte. 80 | */ 81 | typedef union { 82 | unsigned char byte; /**< the whole byte */ 83 | } MQTTHeader; 84 | 85 | IoT_Error_t aws_iot_mqtt_internal_init_header(MQTTHeader *pHeader, MessageTypes message_type, 86 | QoS qos, uint8_t dup, uint8_t retained); 87 | 88 | IoT_Error_t aws_iot_mqtt_internal_serialize_ack(unsigned char *pTxBuf, size_t txBufLen, 89 | MessageTypes msgType, uint8_t dup, uint16_t packetId, 90 | uint32_t *pSerializedLen); 91 | IoT_Error_t aws_iot_mqtt_internal_deserialize_ack(unsigned char *, unsigned char *, 92 | uint16_t *, unsigned char *, size_t); 93 | 94 | uint32_t aws_iot_mqtt_internal_get_final_packet_length_from_remaining_length(uint32_t rem_len); 95 | 96 | size_t aws_iot_mqtt_internal_write_len_to_buffer(unsigned char *buf, uint32_t length); 97 | IoT_Error_t aws_iot_mqtt_internal_decode_remaining_length_from_buffer(unsigned char *buf, uint32_t *decodedLen, 98 | uint32_t *readBytesLen); 99 | 100 | uint16_t aws_iot_mqtt_internal_read_uint16_t(unsigned char **pptr); 101 | void aws_iot_mqtt_internal_write_uint_16(unsigned char **pptr, uint16_t anInt); 102 | 103 | unsigned char aws_iot_mqtt_internal_read_char(unsigned char **pptr); 104 | void aws_iot_mqtt_internal_write_char(unsigned char **pptr, unsigned char c); 105 | void aws_iot_mqtt_internal_write_utf8_string(unsigned char **pptr, const char *string, uint16_t stringLen); 106 | 107 | IoT_Error_t aws_iot_mqtt_internal_flushBuffers( AWS_IoT_Client *pClient ); 108 | IoT_Error_t aws_iot_mqtt_internal_send_packet(AWS_IoT_Client *pClient, size_t length, Timer *pTimer); 109 | IoT_Error_t aws_iot_mqtt_internal_cycle_read(AWS_IoT_Client *pClient, Timer *pTimer, uint8_t *pPacketType); 110 | IoT_Error_t aws_iot_mqtt_internal_wait_for_read(AWS_IoT_Client *pClient, uint8_t packetType, Timer *pTimer); 111 | IoT_Error_t aws_iot_mqtt_internal_serialize_zero(unsigned char *pTxBuf, size_t txBufLen, 112 | MessageTypes packetType, size_t *pSerializedLength); 113 | IoT_Error_t aws_iot_mqtt_internal_deserialize_publish(uint8_t *dup, QoS *qos, 114 | uint8_t *retained, uint16_t *pPacketId, 115 | char **pTopicName, uint16_t *topicNameLen, 116 | unsigned char **payload, size_t *payloadLen, 117 | unsigned char *pRxBuf, size_t rxBufLen); 118 | 119 | IoT_Error_t aws_iot_mqtt_set_client_state(AWS_IoT_Client *pClient, ClientState expectedCurrentState, 120 | ClientState newState); 121 | 122 | #ifdef _ENABLE_THREAD_SUPPORT_ 123 | 124 | IoT_Error_t aws_iot_mqtt_client_lock_mutex(AWS_IoT_Client *pClient, IoT_Mutex_t *pMutex); 125 | 126 | IoT_Error_t aws_iot_mqtt_client_unlock_mutex(AWS_IoT_Client *pClient, IoT_Mutex_t *pMutex); 127 | 128 | #endif 129 | 130 | #ifdef __cplusplus 131 | } 132 | #endif 133 | 134 | #endif /* AWS_IOT_SDK_SRC_IOT_COMMON_INTERNAL_H */ 135 | -------------------------------------------------------------------------------- /src/aws_iot_jobs_json.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | #define __STDC_FORMAT_MACROS 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "jsmn.h" 29 | #include "aws_iot_jobs_json.h" 30 | 31 | struct _SerializeState { 32 | int totalSize; 33 | char *nextPtr; 34 | size_t remaingSize; 35 | }; 36 | 37 | static void _printToBuffer(struct _SerializeState *state, const char *fmt, ...) { 38 | if (state->totalSize == -1) return; 39 | 40 | va_list vl; 41 | va_start(vl, fmt); 42 | int len = vsnprintf(state->nextPtr, state->remaingSize, fmt, vl); 43 | if (len < 0) { 44 | state->totalSize = -1; 45 | } else { 46 | state->totalSize += len; 47 | if (state->nextPtr != NULL) { 48 | if (state->remaingSize > (size_t) len) { 49 | state->remaingSize -= (size_t) len; 50 | state->nextPtr += len; 51 | } else { 52 | state->remaingSize = 0; 53 | state->nextPtr = NULL; 54 | } 55 | } 56 | } 57 | va_end(vl); 58 | } 59 | 60 | static void _printKey(struct _SerializeState *state, bool first, const char *key) { 61 | if (first) { 62 | _printToBuffer(state, "{\"%s\":", key); 63 | } else { 64 | _printToBuffer(state, ",\"%s\":", key); 65 | } 66 | } 67 | 68 | static void _printStringValue(struct _SerializeState *state, const char *value) { 69 | if (value == NULL) { 70 | _printToBuffer(state, "null"); 71 | } else { 72 | _printToBuffer(state, "\"%s\"", value); 73 | } 74 | } 75 | 76 | static void _printLongValue(struct _SerializeState *state, int64_t value) { 77 | _printToBuffer(state, "%lld", value); 78 | } 79 | 80 | static void _printBooleanValue(struct _SerializeState *state, bool value) { 81 | if(value) { 82 | _printToBuffer(state, "true"); 83 | } else { 84 | _printToBuffer(state, "false"); 85 | } 86 | } 87 | 88 | int aws_iot_jobs_json_serialize_update_job_execution_request( 89 | char *requestBuffer, size_t bufferSize, 90 | const AwsIotJobExecutionUpdateRequest *request) 91 | { 92 | const char *statusStr = aws_iot_jobs_map_status_to_string(request->status); 93 | if (statusStr == NULL) return -1; 94 | if (requestBuffer == NULL) bufferSize = 0; 95 | 96 | struct _SerializeState state = { 0, requestBuffer, bufferSize }; 97 | _printKey(&state, true, "status"); 98 | _printStringValue(&state, statusStr); 99 | if (request->statusDetails != NULL) { 100 | _printKey(&state, false, "statusDetails"); 101 | _printToBuffer(&state, "%s", request->statusDetails); 102 | } 103 | if (request->executionNumber != 0) { 104 | _printKey(&state, false, "executionNumber"); 105 | _printLongValue(&state, request->executionNumber); 106 | } 107 | if (request->expectedVersion != 0) { 108 | _printKey(&state, false, "expectedVersion"); 109 | _printLongValue(&state, request->expectedVersion); 110 | } 111 | if (request->includeJobExecutionState) { 112 | _printKey(&state, false, "includeJobExecutionState"); 113 | _printBooleanValue(&state, request->includeJobExecutionState); 114 | } 115 | if (request->includeJobDocument) { 116 | _printKey(&state, false, "includeJobDocument"); 117 | _printBooleanValue(&state, request->includeJobDocument); 118 | } 119 | if (request->clientToken != NULL) { 120 | _printKey(&state, false, "clientToken"); 121 | _printStringValue(&state, request->clientToken); 122 | } 123 | 124 | _printToBuffer(&state, "}"); 125 | 126 | return state.totalSize; 127 | } 128 | 129 | int aws_iot_jobs_json_serialize_client_token_only_request( 130 | char *requestBuffer, size_t bufferSize, 131 | const char *clientToken) 132 | { 133 | struct _SerializeState state = { 0, requestBuffer, bufferSize }; 134 | _printKey(&state, true, "clientToken"); 135 | _printStringValue(&state, clientToken); 136 | _printToBuffer(&state, "}"); 137 | 138 | return state.totalSize; 139 | } 140 | 141 | int aws_iot_jobs_json_serialize_describe_job_execution_request( 142 | char *requestBuffer, size_t bufferSize, 143 | const AwsIotDescribeJobExecutionRequest *request) 144 | { 145 | bool first = true; 146 | 147 | if (requestBuffer == NULL) return 0; 148 | 149 | struct _SerializeState state = { 0, requestBuffer, bufferSize }; 150 | if (request->clientToken != NULL) { 151 | _printKey(&state, first, "clientToken"); 152 | _printStringValue(&state, request->clientToken); 153 | first = false; 154 | } 155 | if (request->executionNumber != 0) { 156 | _printKey(&state, first, "executionNumber"); 157 | _printLongValue(&state, request->executionNumber); 158 | first = false; 159 | } 160 | if (request->includeJobDocument) { 161 | _printKey(&state, first, "includeJobDocument"); 162 | _printBooleanValue(&state, request->includeJobDocument); 163 | } 164 | 165 | _printToBuffer(&state, "}"); 166 | 167 | return state.totalSize; 168 | } 169 | 170 | int aws_iot_jobs_json_serialize_start_next_job_execution_request( 171 | char *requestBuffer, size_t bufferSize, 172 | const AwsIotStartNextPendingJobExecutionRequest *request) 173 | { 174 | if (requestBuffer == NULL) bufferSize = 0; 175 | struct _SerializeState state = { 0, requestBuffer, bufferSize }; 176 | if (request->statusDetails != NULL) { 177 | _printKey(&state, true, "statusDetails"); 178 | _printToBuffer(&state, "%s", request->statusDetails); 179 | } 180 | if (request->clientToken != NULL) { 181 | if(request->statusDetails != NULL) { 182 | _printKey(&state, false, "clientToken"); 183 | } else { 184 | _printKey(&state, true, "clientToken"); 185 | } 186 | _printStringValue(&state, request->clientToken); 187 | } 188 | if (request->clientToken == NULL && request->statusDetails == NULL) { 189 | _printToBuffer(&state, "{"); 190 | } 191 | _printToBuffer(&state, "}"); 192 | return state.totalSize; 193 | } 194 | 195 | #ifdef __cplusplus 196 | } 197 | #endif 198 | -------------------------------------------------------------------------------- /src/aws_iot_json_utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | /** 17 | * @file aws_json_utils.c 18 | * @brief Utilities for manipulating JSON 19 | * 20 | * json_utils provides JSON parsing utilities for use with the IoT SDK. 21 | * Underlying JSON parsing relies on the Jasmine JSON parser. 22 | * 23 | */ 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif 28 | 29 | #include "aws_iot_json_utils.h" 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | #include "aws_iot_log.h" 36 | 37 | int8_t jsoneq(const char *json, jsmntok_t *tok, const char *s) { 38 | if(tok->type == JSMN_STRING) { 39 | if((int) strlen(s) == tok->end - tok->start) { 40 | if(strncmp(json + tok->start, s, (size_t) (tok->end - tok->start)) == 0) { 41 | return 0; 42 | } 43 | } 44 | } 45 | return -1; 46 | } 47 | 48 | IoT_Error_t parseUnsignedInteger32Value(uint32_t *i, const char *jsonString, jsmntok_t *token) { 49 | if(token->type != JSMN_PRIMITIVE) { 50 | IOT_WARN("Token was not an integer"); 51 | return JSON_PARSE_ERROR; 52 | } 53 | 54 | if(('-' == (char) (jsonString[token->start])) || (1 != sscanf(jsonString + token->start, "%u", i))) { 55 | IOT_WARN("Token was not an unsigned integer."); 56 | return JSON_PARSE_ERROR; 57 | } 58 | 59 | return SUCCESS; 60 | } 61 | 62 | IoT_Error_t parseUnsignedInteger16Value(uint16_t *i, const char *jsonString, jsmntok_t *token) { 63 | if(token->type != JSMN_PRIMITIVE) { 64 | IOT_WARN("Token was not an integer"); 65 | return JSON_PARSE_ERROR; 66 | } 67 | 68 | if(('-' == (char) (jsonString[token->start])) || (1 != sscanf(jsonString + token->start, "%hu", i))) { 69 | IOT_WARN("Token was not an unsigned integer."); 70 | return JSON_PARSE_ERROR; 71 | } 72 | 73 | return SUCCESS; 74 | } 75 | 76 | IoT_Error_t parseUnsignedInteger8Value(uint8_t *i, const char *jsonString, jsmntok_t *token) { 77 | if(token->type != JSMN_PRIMITIVE) { 78 | IOT_WARN("Token was not an integer"); 79 | return JSON_PARSE_ERROR; 80 | } 81 | 82 | if(('-' == (char) (jsonString[token->start])) || (1 != sscanf(jsonString + token->start, "%hhu", i))) { 83 | IOT_WARN("Token was not an unsigned integer."); 84 | return JSON_PARSE_ERROR; 85 | } 86 | 87 | return SUCCESS; 88 | } 89 | 90 | IoT_Error_t parseInteger32Value(int32_t *i, const char *jsonString, jsmntok_t *token) { 91 | if(token->type != JSMN_PRIMITIVE) { 92 | IOT_WARN("Token was not an integer"); 93 | return JSON_PARSE_ERROR; 94 | } 95 | 96 | if(1 != sscanf(jsonString + token->start, "%i", i)) { 97 | IOT_WARN("Token was not an integer."); 98 | return JSON_PARSE_ERROR; 99 | } 100 | 101 | return SUCCESS; 102 | } 103 | 104 | IoT_Error_t parseInteger16Value(int16_t *i, const char *jsonString, jsmntok_t *token) { 105 | if(token->type != JSMN_PRIMITIVE) { 106 | IOT_WARN("Token was not an integer"); 107 | return JSON_PARSE_ERROR; 108 | } 109 | 110 | if(1 != sscanf(jsonString + token->start, "%hi", i)) { 111 | IOT_WARN("Token was not an integer."); 112 | return JSON_PARSE_ERROR; 113 | } 114 | 115 | return SUCCESS; 116 | } 117 | 118 | IoT_Error_t parseInteger8Value(int8_t *i, const char *jsonString, jsmntok_t *token) { 119 | if(token->type != JSMN_PRIMITIVE) { 120 | IOT_WARN("Token was not an integer"); 121 | return JSON_PARSE_ERROR; 122 | } 123 | 124 | if(1 != sscanf(jsonString + token->start, "%hhi", i)) { 125 | IOT_WARN("Token was not an integer."); 126 | return JSON_PARSE_ERROR; 127 | } 128 | 129 | return SUCCESS; 130 | } 131 | 132 | IoT_Error_t parseFloatValue(float *f, const char *jsonString, jsmntok_t *token) { 133 | if(token->type != JSMN_PRIMITIVE) { 134 | IOT_WARN("Token was not a float."); 135 | return JSON_PARSE_ERROR; 136 | } 137 | 138 | if(1 != sscanf(jsonString + token->start, "%f", f)) { 139 | IOT_WARN("Token was not a float."); 140 | return JSON_PARSE_ERROR; 141 | } 142 | 143 | return SUCCESS; 144 | } 145 | 146 | IoT_Error_t parseDoubleValue(double *d, const char *jsonString, jsmntok_t *token) { 147 | if(token->type != JSMN_PRIMITIVE) { 148 | IOT_WARN("Token was not a double."); 149 | return JSON_PARSE_ERROR; 150 | } 151 | 152 | if(1 != sscanf(jsonString + token->start, "%lf", d)) { 153 | IOT_WARN("Token was not a double."); 154 | return JSON_PARSE_ERROR; 155 | } 156 | 157 | return SUCCESS; 158 | } 159 | 160 | IoT_Error_t parseBooleanValue(bool *b, const char *jsonString, jsmntok_t *token) { 161 | if(token->type != JSMN_PRIMITIVE) { 162 | IOT_WARN("Token was not a primitive."); 163 | return JSON_PARSE_ERROR; 164 | } 165 | if(strncmp(jsonString + token->start, "true", 4) == 0) { 166 | *b = true; 167 | } else if(strncmp(jsonString + token->start, "false", 5) == 0) { 168 | *b = false; 169 | } else { 170 | IOT_WARN("Token was not a bool."); 171 | return JSON_PARSE_ERROR; 172 | } 173 | return SUCCESS; 174 | } 175 | 176 | IoT_Error_t parseStringValue(char *buf, size_t bufLen, const char *jsonString, jsmntok_t *token) { 177 | /* This length does not include a null-terminator. */ 178 | size_t stringLength = (size_t)(token->end - token->start); 179 | 180 | if(token->type != JSMN_STRING) { 181 | IOT_WARN("Token was not a string."); 182 | return JSON_PARSE_ERROR; 183 | } 184 | 185 | if (stringLength+1 > bufLen) { 186 | IOT_WARN("Buffer too small to hold string value."); 187 | return SHADOW_JSON_ERROR; 188 | } 189 | 190 | strncpy(buf, jsonString + token->start, stringLength); 191 | buf[stringLength] = '\0'; 192 | 193 | return SUCCESS; 194 | } 195 | 196 | jsmntok_t *findToken(const char *key, const char *jsonString, jsmntok_t *token) { 197 | jsmntok_t *result = token; 198 | int i; 199 | 200 | if(token->type != JSMN_OBJECT) { 201 | IOT_WARN("Token was not an object."); 202 | return NULL; 203 | } 204 | 205 | if(token->size == 0) { 206 | return NULL; 207 | } 208 | 209 | result = token + 1; 210 | 211 | for (i = 0; i < token->size; i++) { 212 | if (0 == jsoneq(jsonString, result, key)) { 213 | return result + 1; 214 | } 215 | 216 | int propertyEnd = (result + 1)->end; 217 | result += 2; 218 | while (result->start < propertyEnd) 219 | result++; 220 | } 221 | 222 | return NULL; 223 | } 224 | 225 | #ifdef __cplusplus 226 | } 227 | #endif 228 | -------------------------------------------------------------------------------- /src/aws_iot_shadow_json_data.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | #ifndef SRC_SHADOW_AWS_IOT_SHADOW_JSON_DATA_H_ 17 | #define SRC_SHADOW_AWS_IOT_SHADOW_JSON_DATA_H_ 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | /** 24 | * @file aws_iot_shadow_json_data.h 25 | * @brief This file is the interface for all the Shadow related JSON functions. 26 | */ 27 | 28 | #include 29 | 30 | /** 31 | * @brief This is a static JSON object that could be used in code 32 | * 33 | */ 34 | typedef struct jsonStruct jsonStruct_t; 35 | 36 | /** 37 | * @brief Every JSON name value can have a callback. The callback should follow this signature 38 | */ 39 | typedef void (*jsonStructCallback_t)(const char *pJsonValueBuffer, uint32_t valueLength, jsonStruct_t *pJsonStruct_t); 40 | 41 | /** 42 | * @brief All the JSON object types enum 43 | * 44 | * JSON number types need to be split into proper integer / floating point data types and sizes on embedded platforms. 45 | */ 46 | typedef enum { 47 | SHADOW_JSON_INT32, 48 | SHADOW_JSON_INT16, 49 | SHADOW_JSON_INT8, 50 | SHADOW_JSON_UINT32, 51 | SHADOW_JSON_UINT16, 52 | SHADOW_JSON_UINT8, 53 | SHADOW_JSON_FLOAT, 54 | SHADOW_JSON_DOUBLE, 55 | SHADOW_JSON_BOOL, 56 | SHADOW_JSON_STRING, 57 | SHADOW_JSON_OBJECT 58 | } JsonPrimitiveType; 59 | 60 | /** 61 | * @brief This is the struct form of a JSON Key value pair 62 | */ 63 | struct jsonStruct { 64 | const char *pKey; ///< JSON key 65 | void *pData; ///< pointer to the data (JSON value) 66 | size_t dataLength; ///< Length (in bytes) of pData 67 | JsonPrimitiveType type; ///< type of JSON 68 | jsonStructCallback_t cb; ///< callback to be executed on receiving the Key value pair 69 | }; 70 | 71 | /** 72 | * @brief Initialize the JSON document with Shadow expected name/value 73 | * 74 | * This Function will fill the JSON Buffer with a null terminated string. Internally it uses snprintf 75 | * This function should always be used First, followed by iot_shadow_add_reported and/or iot_shadow_add_desired. 76 | * Always finish the call sequence with iot_finalize_json_document 77 | * 78 | * @note Ensure the size of the Buffer is enough to hold the entire JSON Document. 79 | * 80 | * 81 | * @param pJsonDocument The JSON Document filled in this char buffer 82 | * @param maxSizeOfJsonDocument maximum size of the pJsonDocument that can be used to fill the JSON document 83 | * @return An IoT Error Type defining if the buffer was null or the entire string was not filled up 84 | */ 85 | IoT_Error_t aws_iot_shadow_init_json_document(char *pJsonDocument, size_t maxSizeOfJsonDocument); 86 | 87 | /** 88 | * @brief Add the reported section of the JSON document of jsonStruct_t 89 | * 90 | * This is a variadic function and please be careful with the usage. count is the number of jsonStruct_t types that you would like to add in the reported section 91 | * This function will add "reported":{} 92 | * 93 | * @note Ensure the size of the Buffer is enough to hold the reported section + the init section. Always use the same JSON document buffer used in the iot_shadow_init_json_document function. This function will accommodate the size of previous null terminated string, so pass teh max size of the buffer 94 | * 95 | * 96 | * @param pJsonDocument The JSON Document filled in this char buffer 97 | * @param maxSizeOfJsonDocument maximum size of the pJsonDocument that can be used to fill the JSON document 98 | * @param count total number of arguments(jsonStruct_t object) passed in the arguments 99 | * @return An IoT Error Type defining if the buffer was null or the entire string was not filled up 100 | */ 101 | IoT_Error_t aws_iot_shadow_add_reported(char *pJsonDocument, size_t maxSizeOfJsonDocument, uint8_t count, ...); 102 | 103 | /** 104 | * @brief Add the desired section of the JSON document of jsonStruct_t 105 | * 106 | * This is a variadic function and please be careful with the usage. count is the number of jsonStruct_t types that you would like to add in the reported section 107 | * This function will add "desired":{} 108 | * 109 | * @note Ensure the size of the Buffer is enough to hold the reported section + the init section. Always use the same JSON document buffer used in the iot_shadow_init_json_document function. This function will accommodate the size of previous null terminated string, so pass the max size of the buffer 110 | * 111 | * 112 | * @param pJsonDocument The JSON Document filled in this char buffer 113 | * @param maxSizeOfJsonDocument maximum size of the pJsonDocument that can be used to fill the JSON document 114 | * @param count total number of arguments(jsonStruct_t object) passed in the arguments 115 | * @return An IoT Error Type defining if the buffer was null or the entire string was not filled up 116 | */ 117 | IoT_Error_t aws_iot_shadow_add_desired(char *pJsonDocument, size_t maxSizeOfJsonDocument, uint8_t count, ...); 118 | 119 | /** 120 | * @brief Finalize the JSON document with Shadow expected client Token. 121 | * 122 | * This function will automatically increment the client token every time this function is called. 123 | * 124 | * @note Ensure the size of the Buffer is enough to hold the entire JSON Document. If the finalized section is not invoked then the JSON doucment will not be valid 125 | * 126 | * 127 | * @param pJsonDocument The JSON Document filled in this char buffer 128 | * @param maxSizeOfJsonDocument maximum size of the pJsonDocument that can be used to fill the JSON document 129 | * @return An IoT Error Type defining if the buffer was null or the entire string was not filled up 130 | */ 131 | IoT_Error_t aws_iot_finalize_json_document(char *pJsonDocument, size_t maxSizeOfJsonDocument); 132 | 133 | /** 134 | * @brief Fill the given buffer with client token for tracking the Repsonse. 135 | * 136 | * This function will add the AWS_IOT_MQTT_CLIENT_ID with a sequence number. Every time this function is used the sequence number gets incremented 137 | * 138 | * 139 | * @param pBufferToBeUpdatedWithClientToken buffer to be updated with the client token string 140 | * @param maxSizeOfJsonDocument maximum size of the pBufferToBeUpdatedWithClientToken that can be used 141 | * @return An IoT Error Type defining if the buffer was null or the entire string was not filled up 142 | */ 143 | 144 | IoT_Error_t aws_iot_fill_with_client_token(char *pBufferToBeUpdatedWithClientToken, size_t maxSizeOfJsonDocument); 145 | 146 | #ifdef __cplusplus 147 | } 148 | #endif 149 | 150 | #endif /* SRC_SHADOW_AWS_IOT_SHADOW_JSON_DATA_H_ */ 151 | -------------------------------------------------------------------------------- /src/aws_iot_json_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | /** 17 | * @file aws_json_utils.h 18 | * @brief Utilities for manipulating JSON 19 | * 20 | * json_utils provides JSON parsing utilities for use with the IoT SDK. 21 | * Underlying JSON parsing relies on the Jasmine JSON parser. 22 | * 23 | */ 24 | 25 | #ifndef AWS_IOT_SDK_SRC_JSON_UTILS_H_ 26 | #define AWS_IOT_SDK_SRC_JSON_UTILS_H_ 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | #include 33 | #include 34 | 35 | #include "aws_iot_error.h" 36 | #include "jsmn.h" 37 | 38 | // utility functions 39 | /** 40 | * @brief JSON Equality Check 41 | * 42 | * Given a token pointing to a particular JSON node and an 43 | * input string, check to see if the key is equal to the string. 44 | * 45 | * @param json json string 46 | * @param tok json token - pointer to key to test for equality 47 | * @param s input string for key to test equality 48 | * 49 | * @return 0 if equal, 1 otherwise 50 | */ 51 | int8_t jsoneq(const char *json, jsmntok_t *tok, const char *s); 52 | 53 | /** 54 | * @brief Parse a signed 32-bit integer value from a JSON node. 55 | * 56 | * Given a JSON node parse the integer value from the value. 57 | * 58 | * @param jsonString json string 59 | * @param tok json token - pointer to JSON node 60 | * @param i address of int32_t to be updated 61 | * 62 | * @return SUCCESS - success 63 | * @return JSON_PARSE_ERROR - error parsing value 64 | */ 65 | IoT_Error_t parseInteger32Value(int32_t *i, const char *jsonString, jsmntok_t *token); 66 | 67 | /** 68 | * @brief Parse a signed 16-bit integer value from a JSON node. 69 | * 70 | * Given a JSON node parse the integer value from the value. 71 | * 72 | * @param jsonString json string 73 | * @param tok json token - pointer to JSON node 74 | * @param i address of int16_t to be updated 75 | * 76 | * @return SUCCESS - success 77 | * @return JSON_PARSE_ERROR - error parsing value 78 | */ 79 | IoT_Error_t parseInteger16Value(int16_t *i, const char *jsonString, jsmntok_t *token); 80 | 81 | /** 82 | * @brief Parse a signed 8-bit integer value from a JSON node. 83 | * 84 | * Given a JSON node parse the integer value from the value. 85 | * 86 | * @param jsonString json string 87 | * @param tok json token - pointer to JSON node 88 | * @param i address of int8_t to be updated 89 | * 90 | * @return SUCCESS - success 91 | * @return JSON_PARSE_ERROR - error parsing value 92 | */ 93 | IoT_Error_t parseInteger8Value(int8_t *i, const char *jsonString, jsmntok_t *token); 94 | 95 | /** 96 | * @brief Parse an unsigned 32-bit integer value from a JSON node. 97 | * 98 | * Given a JSON node parse the integer value from the value. 99 | * 100 | * @param jsonString json string 101 | * @param tok json token - pointer to JSON node 102 | * @param i address of uint32_t to be updated 103 | * 104 | * @return SUCCESS - success 105 | * @return JSON_PARSE_ERROR - error parsing value 106 | */ 107 | IoT_Error_t parseUnsignedInteger32Value(uint32_t *i, const char *jsonString, jsmntok_t *token); 108 | 109 | /** 110 | * @brief Parse an unsigned 16-bit integer value from a JSON node. 111 | * 112 | * Given a JSON node parse the integer value from the value. 113 | * 114 | * @param jsonString json string 115 | * @param tok json token - pointer to JSON node 116 | * @param i address of uint16_t to be updated 117 | * 118 | * @return SUCCESS - success 119 | * @return JSON_PARSE_ERROR - error parsing value 120 | */ 121 | IoT_Error_t parseUnsignedInteger16Value(uint16_t *i, const char *jsonString, jsmntok_t *token); 122 | 123 | /** 124 | * @brief Parse an unsigned 8-bit integer value from a JSON node. 125 | * 126 | * Given a JSON node parse the integer value from the value. 127 | * 128 | * @param jsonString json string 129 | * @param tok json token - pointer to JSON node 130 | * @param i address of uint8_t to be updated 131 | * 132 | * @return SUCCESS - success 133 | * @return JSON_PARSE_ERROR - error parsing value 134 | */ 135 | IoT_Error_t parseUnsignedInteger8Value(uint8_t *i, const char *jsonString, jsmntok_t *token); 136 | 137 | /** 138 | * @brief Parse a float value from a JSON node. 139 | * 140 | * Given a JSON node parse the float value from the value. 141 | * 142 | * @param jsonString json string 143 | * @param tok json token - pointer to JSON node 144 | * @param f address of float to be updated 145 | * 146 | * @return SUCCESS - success 147 | * @return JSON_PARSE_ERROR - error parsing value 148 | */ 149 | IoT_Error_t parseFloatValue(float *f, const char *jsonString, jsmntok_t *token); 150 | 151 | /** 152 | * @brief Parse a double value from a JSON node. 153 | * 154 | * Given a JSON node parse the double value from the value. 155 | * 156 | * @param jsonString json string 157 | * @param tok json token - pointer to JSON node 158 | * @param d address of double to be updated 159 | * 160 | * @return SUCCESS - success 161 | * @return JSON_PARSE_ERROR - error parsing value 162 | */ 163 | IoT_Error_t parseDoubleValue(double *d, const char *jsonString, jsmntok_t *token); 164 | 165 | /** 166 | * @brief Parse a boolean value from a JSON node. 167 | * 168 | * Given a JSON node parse the boolean value from the value. 169 | * 170 | * @param jsonString json string 171 | * @param tok json token - pointer to JSON node 172 | * @param b address of boolean to be updated 173 | * 174 | * @return SUCCESS - success 175 | * @return JSON_PARSE_ERROR - error parsing value 176 | */ 177 | IoT_Error_t parseBooleanValue(bool *b, const char *jsonString, jsmntok_t *token); 178 | 179 | /** 180 | * @brief Parse a string value from a JSON node. 181 | * 182 | * Given a JSON node parse the string value from the value. 183 | * 184 | * @param buf address of string to be updated 185 | * @param bufLen length of buf in bytes 186 | * @param jsonString json string 187 | * @param token json token - pointer to JSON node 188 | * 189 | * @return SUCCESS - success 190 | * @return JSON_PARSE_ERROR - error parsing value 191 | */ 192 | IoT_Error_t parseStringValue(char *buf, size_t bufLen, const char *jsonString, jsmntok_t *token); 193 | 194 | /** 195 | * @brief Find the JSON node associated with the given key in the given object. 196 | * 197 | * Given a JSON node parse the string value from the value. 198 | * 199 | * @param key json key 200 | * @param token json token - pointer to JSON node 201 | * @param jsonString json string 202 | * 203 | * @return pointer to found property value 204 | * @return NULL - not found 205 | */ 206 | jsmntok_t *findToken(const char *key, const char *jsonString, jsmntok_t *token); 207 | 208 | #ifdef __cplusplus 209 | } 210 | #endif 211 | 212 | #endif /* AWS_IOT_SDK_SRC_JSON_UTILS_H_ */ 213 | -------------------------------------------------------------------------------- /src/network_interface.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | /** 17 | * @file network_interface.h 18 | * @brief Network interface definition for MQTT client. 19 | * 20 | * Defines an interface to the TLS layer to be used by the MQTT client. 21 | * Starting point for porting the SDK to the networking layer of a new platform. 22 | */ 23 | 24 | #ifndef __NETWORK_INTERFACE_H_ 25 | #define __NETWORK_INTERFACE_H_ 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | #include 32 | #include 33 | #include 34 | #include "timer_interface.h" 35 | #include "network_platform.h" 36 | 37 | /** 38 | * @brief Network Type 39 | * 40 | * Defines a type for the network struct. See structure definition below. 41 | */ 42 | typedef struct Network Network; 43 | 44 | /** 45 | * @brief TLS Connection Parameters 46 | * 47 | * Defines a type containing TLS specific parameters to be passed down to the 48 | * TLS networking layer to create a TLS secured socket. 49 | */ 50 | typedef struct { 51 | char *pRootCALocation; ///< Pointer to string containing the filename (including path) of the root CA file. 52 | char *pDeviceCertLocation; ///< Pointer to string containing the filename (including path) of the device certificate. 53 | char *pDevicePrivateKeyLocation; ///< Pointer to string containing the filename (including path) of the device private key file. 54 | char *pDestinationURL; ///< Pointer to string containing the endpoint of the MQTT service. 55 | uint16_t DestinationPort; ///< Integer defining the connection port of the MQTT service. 56 | uint32_t timeout_ms; ///< Unsigned integer defining the TLS handshake timeout value in milliseconds. 57 | bool ServerVerificationFlag; ///< Boolean. True = perform server certificate hostname validation. False = skip validation \b NOT recommended. 58 | } TLSConnectParams; 59 | 60 | /** 61 | * @brief Network Structure 62 | * 63 | * Structure for defining a network connection. 64 | */ 65 | struct Network { 66 | IoT_Error_t (*connect)(Network *, TLSConnectParams *); 67 | 68 | IoT_Error_t (*read)(Network *, unsigned char *, size_t, Timer *, size_t *); ///< Function pointer pointing to the network function to read from the network 69 | IoT_Error_t (*write)(Network *, unsigned char *, size_t, Timer *, size_t *); ///< Function pointer pointing to the network function to write to the network 70 | IoT_Error_t (*disconnect)(Network *); ///< Function pointer pointing to the network function to disconnect from the network 71 | IoT_Error_t (*isConnected)(Network *); ///< Function pointer pointing to the network function to check if TLS is connected 72 | IoT_Error_t (*destroy)(Network *); ///< Function pointer pointing to the network function to destroy the network object 73 | 74 | TLSConnectParams tlsConnectParams; ///< TLSConnect params structure containing the common connection parameters 75 | TLSDataParams tlsDataParams; ///< TLSData params structure containing the connection data parameters that are specific to the library being used 76 | }; 77 | 78 | /** 79 | * @brief Initialize the TLS implementation 80 | * 81 | * Perform any initialization required by the TLS layer. 82 | * Connects the interface to implementation by setting up 83 | * the network layer function pointers to platform implementations. 84 | * 85 | * @param pNetwork - Pointer to a Network struct defining the network interface. 86 | * @param pRootCALocation - Path of the location of the Root CA 87 | * @param pDeviceCertLocation - Path to the location of the Device Cert 88 | * @param pDevicyPrivateKeyLocation - Path to the location of the device private key file 89 | * @param pDestinationURL - The target endpoint to connect to 90 | * @param DestinationPort - The port on the target to connect to 91 | * @param timeout_ms - The value to use for timeout of operation 92 | * @param ServerVerificationFlag - used to decide whether server verification is needed or not 93 | * 94 | * @return IoT_Error_t - successful initialization or TLS error 95 | */ 96 | IoT_Error_t iot_tls_init(Network *pNetwork, char *pRootCALocation, char *pDeviceCertLocation, 97 | char *pDevicePrivateKeyLocation, char *pDestinationURL, 98 | uint16_t DestinationPort, uint32_t timeout_ms, bool ServerVerificationFlag); 99 | 100 | /** 101 | * @brief Create a TLS socket and open the connection 102 | * 103 | * Creates an open socket connection including TLS handshake. 104 | * 105 | * @param pNetwork - Pointer to a Network struct defining the network interface. 106 | * @param TLSParams - TLSConnectParams defines the properties of the TLS connection. 107 | * @return IoT_Error_t - successful connection or TLS error 108 | */ 109 | IoT_Error_t iot_tls_connect(Network *pNetwork, TLSConnectParams *TLSParams); 110 | 111 | /** 112 | * @brief Write bytes to the network socket 113 | * 114 | * @param Network - Pointer to a Network struct defining the network interface. 115 | * @param unsigned char pointer - buffer to write to socket 116 | * @param integer - number of bytes to write 117 | * @param Timer * - operation timer 118 | * @return integer - number of bytes written or TLS error 119 | * @return IoT_Error_t - successful write or TLS error code 120 | */ 121 | IoT_Error_t iot_tls_write(Network *, unsigned char *, size_t, Timer *, size_t *); 122 | 123 | /** 124 | * @brief Read bytes from the network socket 125 | * 126 | * @param Network - Pointer to a Network struct defining the network interface. 127 | * @param unsigned char pointer - pointer to buffer where read bytes should be copied 128 | * @param size_t - number of bytes to read 129 | * @param Timer * - operation timer 130 | * @param size_t - pointer to store number of bytes read 131 | * @return IoT_Error_t - successful read or TLS error code 132 | */ 133 | IoT_Error_t iot_tls_read(Network *, unsigned char *, size_t, Timer *, size_t *); 134 | 135 | /** 136 | * @brief Disconnect from network socket 137 | * 138 | * @param Network - Pointer to a Network struct defining the network interface. 139 | * @return IoT_Error_t - successful read or TLS error code 140 | */ 141 | IoT_Error_t iot_tls_disconnect(Network *pNetwork); 142 | 143 | /** 144 | * @brief Perform any tear-down or cleanup of TLS layer 145 | * 146 | * Called to cleanup any resources required for the TLS layer. 147 | * 148 | * @param Network - Pointer to a Network struct defining the network interface 149 | * @return IoT_Error_t - successful cleanup or TLS error code 150 | */ 151 | IoT_Error_t iot_tls_destroy(Network *pNetwork); 152 | 153 | /** 154 | * @brief Check if TLS layer is still connected 155 | * 156 | * Called to check if the TLS layer is still connected or not. 157 | * 158 | * @param Network - Pointer to a Network struct defining the network interface 159 | * @return IoT_Error_t - TLS error code indicating status of network physical layer connection 160 | */ 161 | IoT_Error_t iot_tls_is_connected(Network *pNetwork); 162 | 163 | #ifdef __cplusplus 164 | } 165 | #endif 166 | 167 | #endif //__NETWORK_INTERFACE_H_ 168 | -------------------------------------------------------------------------------- /src/aws_iot_error.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | /** 17 | * @file aws_iot_error.h 18 | * @brief Definition of error types for the SDK. 19 | */ 20 | 21 | #ifndef AWS_IOT_SDK_SRC_IOT_ERROR_H_ 22 | #define AWS_IOT_SDK_SRC_IOT_ERROR_H_ 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | /* Used to avoid warnings in case of unused parameters in function pointers */ 29 | #define IOT_UNUSED(x) (void)(x) 30 | 31 | /*! \public 32 | * @brief IoT Error enum 33 | * 34 | * Enumeration of return values from the IoT_* functions within the SDK. 35 | * Values less than -1 are specific error codes 36 | * Value of -1 is a generic failure response 37 | * Value of 0 is a generic success response 38 | * Values greater than 0 are specific non-error return codes 39 | */ 40 | typedef enum { 41 | /** Returned when the Network physical layer is connected */ 42 | NETWORK_PHYSICAL_LAYER_CONNECTED = 6, 43 | /** Returned when the Network is manually disconnected */ 44 | NETWORK_MANUALLY_DISCONNECTED = 5, 45 | /** Returned when the Network is disconnected and the reconnect attempt is in progress */ 46 | NETWORK_ATTEMPTING_RECONNECT = 4, 47 | /** Return value of yield function to indicate auto-reconnect was successful */ 48 | NETWORK_RECONNECTED = 3, 49 | /** Returned when a read attempt is made on the TLS buffer and it is empty */ 50 | MQTT_NOTHING_TO_READ = 2, 51 | /** Returned when a connection request is successful and packet response is connection accepted */ 52 | MQTT_CONNACK_CONNECTION_ACCEPTED = 1, 53 | /** Success return value - no error occurred */ 54 | SUCCESS = 0, 55 | /** A generic error. Not enough information for a specific error code */ 56 | FAILURE = -1, 57 | /** A required parameter was passed as null */ 58 | NULL_VALUE_ERROR = -2, 59 | /** The TCP socket could not be established */ 60 | TCP_CONNECTION_ERROR = -3, 61 | /** The TLS handshake failed */ 62 | SSL_CONNECTION_ERROR = -4, 63 | /** Error associated with setting up the parameters of a Socket */ 64 | TCP_SETUP_ERROR = -5, 65 | /** A timeout occurred while waiting for the TLS handshake to complete. */ 66 | NETWORK_SSL_CONNECT_TIMEOUT_ERROR = -6, 67 | /** A Generic write error based on the platform used */ 68 | NETWORK_SSL_WRITE_ERROR = -7, 69 | /** SSL initialization error at the TLS layer */ 70 | NETWORK_SSL_INIT_ERROR = -8, 71 | /** An error occurred when loading the certificates. The certificates could not be located or are incorrectly formatted. */ 72 | NETWORK_SSL_CERT_ERROR = -9, 73 | /** SSL Write times out */ 74 | NETWORK_SSL_WRITE_TIMEOUT_ERROR = -10, 75 | /** SSL Read times out */ 76 | NETWORK_SSL_READ_TIMEOUT_ERROR = -11, 77 | /** A Generic error based on the platform used */ 78 | NETWORK_SSL_READ_ERROR = -12, 79 | /** Returned when the Network is disconnected and reconnect is either disabled or physical layer is disconnected */ 80 | NETWORK_DISCONNECTED_ERROR = -13, 81 | /** Returned when the Network is disconnected and the reconnect attempt has timed out */ 82 | NETWORK_RECONNECT_TIMED_OUT_ERROR = -14, 83 | /** Returned when the Network is already connected and a connection attempt is made */ 84 | NETWORK_ALREADY_CONNECTED_ERROR = -15, 85 | /** Network layer Error Codes */ 86 | /** Network layer Random number generator seeding failed */ 87 | NETWORK_MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED = -16, 88 | /** A generic error code for Network layer errors */ 89 | NETWORK_SSL_UNKNOWN_ERROR = -17, 90 | /** Returned when the physical layer is disconnected */ 91 | NETWORK_PHYSICAL_LAYER_DISCONNECTED = -18, 92 | /** Returned when the root certificate is invalid */ 93 | NETWORK_X509_ROOT_CRT_PARSE_ERROR = -19, 94 | /** Returned when the device certificate is invalid */ 95 | NETWORK_X509_DEVICE_CRT_PARSE_ERROR = -20, 96 | /** Returned when the private key failed to parse */ 97 | NETWORK_PK_PRIVATE_KEY_PARSE_ERROR = -21, 98 | /** Returned when the network layer failed to open a socket */ 99 | NETWORK_ERR_NET_SOCKET_FAILED = -22, 100 | /** Returned when the server is unknown */ 101 | NETWORK_ERR_NET_UNKNOWN_HOST = -23, 102 | /** Returned when connect request failed */ 103 | NETWORK_ERR_NET_CONNECT_FAILED = -24, 104 | /** Returned when there is nothing to read in the TLS read buffer */ 105 | NETWORK_SSL_NOTHING_TO_READ = -25, 106 | /** A connection could not be established. */ 107 | MQTT_CONNECTION_ERROR = -26, 108 | /** A timeout occurred while waiting for the TLS handshake to complete */ 109 | MQTT_CONNECT_TIMEOUT_ERROR = -27, 110 | /** A timeout occurred while waiting for the TLS request complete */ 111 | MQTT_REQUEST_TIMEOUT_ERROR = -28, 112 | /** The current client state does not match the expected value */ 113 | MQTT_UNEXPECTED_CLIENT_STATE_ERROR = -29, 114 | /** The client state is not idle when request is being made */ 115 | MQTT_CLIENT_NOT_IDLE_ERROR = -30, 116 | /** The MQTT RX buffer received corrupt or unexpected message */ 117 | MQTT_RX_MESSAGE_PACKET_TYPE_INVALID_ERROR = -31, 118 | /** The MQTT RX buffer received a bigger message. The message will be dropped */ 119 | MQTT_RX_BUFFER_TOO_SHORT_ERROR = -32, 120 | /** The MQTT TX buffer is too short for the outgoing message. Request will fail */ 121 | MQTT_TX_BUFFER_TOO_SHORT_ERROR = -33, 122 | /** The client is subscribed to the maximum possible number of subscriptions */ 123 | MQTT_MAX_SUBSCRIPTIONS_REACHED_ERROR = -34, 124 | /** Failed to decode the remaining packet length on incoming packet */ 125 | MQTT_DECODE_REMAINING_LENGTH_ERROR = -35, 126 | /** Connect request failed with the server returning an unknown error */ 127 | MQTT_CONNACK_UNKNOWN_ERROR = -36, 128 | /** Connect request failed with the server returning an unacceptable protocol version error */ 129 | MQTT_CONNACK_UNACCEPTABLE_PROTOCOL_VERSION_ERROR = -37, 130 | /** Connect request failed with the server returning an identifier rejected error */ 131 | MQTT_CONNACK_IDENTIFIER_REJECTED_ERROR = -38, 132 | /** Connect request failed with the server returning an unavailable error */ 133 | MQTT_CONNACK_SERVER_UNAVAILABLE_ERROR = -39, 134 | /** Connect request failed with the server returning a bad userdata error */ 135 | MQTT_CONNACK_BAD_USERDATA_ERROR = -40, 136 | /** Connect request failed with the server failing to authenticate the request */ 137 | MQTT_CONNACK_NOT_AUTHORIZED_ERROR = -41, 138 | /** An error occurred while parsing the JSON string. Usually malformed JSON. */ 139 | JSON_PARSE_ERROR = -42, 140 | /** Shadow: The response Ack table is currently full waiting for previously published updates */ 141 | SHADOW_WAIT_FOR_PUBLISH = -43, 142 | /** Any time an snprintf writes more than size value, this error will be returned */ 143 | SHADOW_JSON_BUFFER_TRUNCATED = -44, 144 | /** Any time an snprintf encounters an encoding error or not enough space in the given buffer */ 145 | SHADOW_JSON_ERROR = -45, 146 | /** Mutex initialization failed */ 147 | MUTEX_INIT_ERROR = -46, 148 | /** Mutex lock request failed */ 149 | MUTEX_LOCK_ERROR = -47, 150 | /** Mutex unlock request failed */ 151 | MUTEX_UNLOCK_ERROR = -48, 152 | /** Mutex destroy failed */ 153 | MUTEX_DESTROY_ERROR = -49, 154 | /** Input argument exceeded the allowed maximum size */ 155 | MAX_SIZE_ERROR = -50, 156 | /** Some limit has been exceeded, e.g. the maximum number of subscriptions has been reached */ 157 | LIMIT_EXCEEDED_ERROR = -51, 158 | /** Invalid input topic type */ 159 | INVALID_TOPIC_TYPE_ERROR = -52 160 | } IoT_Error_t; 161 | 162 | #ifdef __cplusplus 163 | } 164 | #endif 165 | 166 | #endif /* AWS_IOT_SDK_SRC_IOT_ERROR_H_ */ 167 | -------------------------------------------------------------------------------- /src/aws_iot_jobs_interface.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | #include "aws_iot_jobs_interface.h" 17 | #include "aws_iot_log.h" 18 | #include "aws_iot_jobs_json.h" 19 | #include 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif 24 | 25 | #define CHECK_GENERATE_STRING_RESULT(result, bufferSize) \ 26 | if (result < 0) { \ 27 | return FAILURE; \ 28 | } else if ((unsigned) result >= bufferSize) { \ 29 | return LIMIT_EXCEEDED_ERROR; \ 30 | } 31 | 32 | 33 | IoT_Error_t aws_iot_jobs_subscribe_to_job_messages( 34 | AWS_IoT_Client *pClient, QoS qos, 35 | const char *thingName, 36 | const char *jobId, 37 | AwsIotJobExecutionTopicType topicType, 38 | AwsIotJobExecutionTopicReplyType replyType, 39 | pApplicationHandler_t pApplicationHandler, 40 | void *pApplicationHandlerData, 41 | char *topicBuffer, 42 | uint16_t topicBufferSize) 43 | { 44 | int requiredSize = aws_iot_jobs_get_api_topic(topicBuffer, topicBufferSize, topicType, replyType, thingName, jobId); 45 | CHECK_GENERATE_STRING_RESULT(requiredSize, topicBufferSize); 46 | 47 | return aws_iot_mqtt_subscribe(pClient, topicBuffer, (uint16_t)strlen(topicBuffer), qos, pApplicationHandler, pApplicationHandlerData); 48 | } 49 | 50 | IoT_Error_t aws_iot_jobs_subscribe_to_all_job_messages( 51 | AWS_IoT_Client *pClient, QoS qos, 52 | const char *thingName, 53 | pApplicationHandler_t pApplicationHandler, 54 | void *pApplicationHandlerData, 55 | char *topicBuffer, 56 | uint16_t topicBufferSize) 57 | { 58 | return aws_iot_jobs_subscribe_to_job_messages(pClient, qos, thingName, NULL, JOB_WILDCARD_TOPIC, JOB_WILDCARD_REPLY_TYPE, 59 | pApplicationHandler, pApplicationHandlerData, topicBuffer, topicBufferSize); 60 | } 61 | 62 | IoT_Error_t aws_iot_jobs_unsubscribe_from_job_messages( 63 | AWS_IoT_Client *pClient, 64 | char *topicBuffer) 65 | { 66 | return aws_iot_mqtt_unsubscribe(pClient, topicBuffer, (uint16_t)strlen(topicBuffer)); 67 | } 68 | 69 | IoT_Error_t aws_iot_jobs_send_query( 70 | AWS_IoT_Client *pClient, QoS qos, 71 | const char *thingName, 72 | const char *jobId, 73 | const char *clientToken, 74 | char *topicBuffer, 75 | uint16_t topicBufferSize, 76 | char *messageBuffer, 77 | size_t messageBufferSize, 78 | AwsIotJobExecutionTopicType topicType) 79 | { 80 | if (thingName == NULL || topicBuffer == NULL || (clientToken != NULL && messageBuffer == NULL)) { 81 | return NULL_VALUE_ERROR; 82 | } 83 | 84 | int neededSize = aws_iot_jobs_get_api_topic(topicBuffer, topicBufferSize, topicType, JOB_REQUEST_TYPE, thingName, jobId); 85 | CHECK_GENERATE_STRING_RESULT(neededSize, topicBufferSize); 86 | uint16_t topicSize = (uint16_t) neededSize; 87 | 88 | char emptyBuffer[1]; 89 | size_t messageLength; 90 | if (clientToken == NULL) { 91 | messageLength = 0; 92 | messageBuffer = emptyBuffer; 93 | } else { 94 | int serializeResult = aws_iot_jobs_json_serialize_client_token_only_request(messageBuffer, messageBufferSize, clientToken); 95 | CHECK_GENERATE_STRING_RESULT(serializeResult, messageBufferSize); 96 | messageLength = (size_t)serializeResult; 97 | } 98 | 99 | IoT_Publish_Message_Params publishParams; 100 | publishParams.qos = qos; 101 | publishParams.isRetained = 0; 102 | publishParams.isDup = 0; 103 | publishParams.id = 0; 104 | publishParams.payload = messageBuffer; 105 | publishParams.payloadLen = messageLength; 106 | 107 | return aws_iot_mqtt_publish(pClient, topicBuffer, topicSize, &publishParams); 108 | } 109 | 110 | IoT_Error_t aws_iot_jobs_start_next( 111 | AWS_IoT_Client *pClient, QoS qos, 112 | const char *thingName, 113 | const AwsIotStartNextPendingJobExecutionRequest *startNextRequest, 114 | char *topicBuffer, 115 | uint16_t topicBufferSize, 116 | char *messageBuffer, 117 | size_t messageBufferSize) 118 | { 119 | if (thingName == NULL || topicBuffer == NULL || startNextRequest == NULL) { 120 | return NULL_VALUE_ERROR; 121 | } 122 | 123 | int neededSize = aws_iot_jobs_get_api_topic(topicBuffer, topicBufferSize, JOB_START_NEXT_TOPIC, JOB_REQUEST_TYPE, thingName, NULL); 124 | CHECK_GENERATE_STRING_RESULT(neededSize, topicBufferSize); 125 | uint16_t topicSize = (uint16_t) neededSize; 126 | 127 | int serializeResult = aws_iot_jobs_json_serialize_start_next_job_execution_request(messageBuffer, messageBufferSize, startNextRequest); 128 | CHECK_GENERATE_STRING_RESULT(serializeResult, messageBufferSize); 129 | 130 | IoT_Publish_Message_Params publishParams; 131 | publishParams.qos = qos; 132 | publishParams.isRetained = 0; 133 | publishParams.isDup = 0; 134 | publishParams.id = 0; 135 | publishParams.payload = messageBuffer; 136 | publishParams.payloadLen = (size_t) serializeResult; 137 | 138 | return aws_iot_mqtt_publish(pClient, topicBuffer, topicSize, &publishParams); 139 | } 140 | 141 | IoT_Error_t aws_iot_jobs_describe( 142 | AWS_IoT_Client *pClient, QoS qos, 143 | const char *thingName, 144 | const char *jobId, 145 | const AwsIotDescribeJobExecutionRequest *describeRequest, 146 | char *topicBuffer, 147 | uint16_t topicBufferSize, 148 | char *messageBuffer, 149 | size_t messageBufferSize) 150 | { 151 | if (thingName == NULL || topicBuffer == NULL || describeRequest == NULL) { 152 | return NULL_VALUE_ERROR; 153 | } 154 | 155 | int neededSize = aws_iot_jobs_get_api_topic(topicBuffer, topicBufferSize, JOB_DESCRIBE_TOPIC, JOB_REQUEST_TYPE, thingName, jobId); 156 | CHECK_GENERATE_STRING_RESULT(neededSize, topicBufferSize); 157 | uint16_t topicSize = (uint16_t) neededSize; 158 | 159 | char emptyBuffer[1]; 160 | size_t messageLength; 161 | if (messageBuffer == NULL) { 162 | messageLength = 0; 163 | messageBuffer = emptyBuffer; 164 | } else { 165 | int serializeResult = aws_iot_jobs_json_serialize_describe_job_execution_request(messageBuffer, messageBufferSize, describeRequest); 166 | CHECK_GENERATE_STRING_RESULT(serializeResult, messageBufferSize); 167 | messageLength = (size_t) serializeResult; 168 | } 169 | 170 | IoT_Publish_Message_Params publishParams; 171 | publishParams.qos = qos; 172 | publishParams.isRetained = 0; 173 | publishParams.isDup = 0; 174 | publishParams.id = 0; 175 | publishParams.payload = messageBuffer; 176 | publishParams.payloadLen = messageLength; 177 | 178 | return aws_iot_mqtt_publish(pClient, topicBuffer, topicSize, &publishParams); 179 | } 180 | 181 | IoT_Error_t aws_iot_jobs_send_update( 182 | AWS_IoT_Client *pClient, QoS qos, 183 | const char *thingName, 184 | const char *jobId, 185 | const AwsIotJobExecutionUpdateRequest *updateRequest, 186 | char *topicBuffer, 187 | uint16_t topicBufferSize, 188 | char *messageBuffer, 189 | size_t messageBufferSize) 190 | { 191 | if (thingName == NULL || topicBuffer == NULL || jobId == NULL || updateRequest == NULL) { 192 | return NULL_VALUE_ERROR; 193 | } 194 | 195 | int neededSize = aws_iot_jobs_get_api_topic(topicBuffer, topicBufferSize, JOB_UPDATE_TOPIC, JOB_REQUEST_TYPE, thingName, jobId); 196 | CHECK_GENERATE_STRING_RESULT(neededSize, topicBufferSize); 197 | uint16_t topicSize = (uint16_t) neededSize; 198 | 199 | int serializeResult = aws_iot_jobs_json_serialize_update_job_execution_request(messageBuffer, messageBufferSize, updateRequest); 200 | CHECK_GENERATE_STRING_RESULT(serializeResult, messageBufferSize); 201 | 202 | IoT_Publish_Message_Params publishParams; 203 | publishParams.qos = qos; 204 | publishParams.isRetained = 0; 205 | publishParams.isDup = 0; 206 | publishParams.id = 0; 207 | publishParams.payload = messageBuffer; 208 | publishParams.payloadLen = (size_t) serializeResult; 209 | 210 | return aws_iot_mqtt_publish(pClient, topicBuffer, topicSize, &publishParams); 211 | } 212 | 213 | #ifdef __cplusplus 214 | } 215 | #endif 216 | -------------------------------------------------------------------------------- /src/aws_iot_shadow.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | /** 17 | * @file aws_iot_shadow.c 18 | * @brief Shadow client API definitions 19 | */ 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif 24 | 25 | #include 26 | #include "aws_iot_mqtt_client_interface.h" 27 | #include "aws_iot_shadow_interface.h" 28 | #include "aws_iot_error.h" 29 | #include "aws_iot_log.h" 30 | #include "aws_iot_shadow_actions.h" 31 | #include "aws_iot_shadow_json.h" 32 | #include "aws_iot_shadow_key.h" 33 | #include "aws_iot_shadow_records.h" 34 | 35 | const ShadowInitParameters_t ShadowInitParametersDefault = {(char *) AWS_IOT_MQTT_HOST, AWS_IOT_MQTT_PORT, NULL, NULL, 36 | NULL, false, NULL}; 37 | 38 | const ShadowConnectParameters_t ShadowConnectParametersDefault = {(char *) AWS_IOT_MY_THING_NAME, 39 | (char *) AWS_IOT_MQTT_CLIENT_ID, 0, NULL}; 40 | 41 | static char deleteAcceptedTopic[MAX_SHADOW_TOPIC_LENGTH_BYTES]; 42 | 43 | void aws_iot_shadow_reset_last_received_version(void) { 44 | shadowJsonVersionNum = 0; 45 | } 46 | 47 | uint32_t aws_iot_shadow_get_last_received_version(void) { 48 | return shadowJsonVersionNum; 49 | } 50 | 51 | void aws_iot_shadow_enable_discard_old_delta_msgs(void) { 52 | shadowDiscardOldDeltaFlag = true; 53 | } 54 | 55 | void aws_iot_shadow_disable_discard_old_delta_msgs(void) { 56 | shadowDiscardOldDeltaFlag = false; 57 | } 58 | 59 | IoT_Error_t aws_iot_shadow_free(AWS_IoT_Client *pClient) 60 | { 61 | IoT_Error_t rc; 62 | 63 | if (NULL == pClient) { 64 | FUNC_EXIT_RC(NULL_VALUE_ERROR); 65 | } 66 | 67 | rc = aws_iot_mqtt_free(pClient); 68 | 69 | FUNC_EXIT_RC(rc); 70 | } 71 | 72 | IoT_Error_t aws_iot_shadow_init(AWS_IoT_Client *pClient, ShadowInitParameters_t *pParams) { 73 | IoT_Client_Init_Params mqttInitParams = IoT_Client_Init_Params_initializer; 74 | IoT_Error_t rc; 75 | 76 | FUNC_ENTRY; 77 | 78 | if(NULL == pClient || NULL == pParams) { 79 | FUNC_EXIT_RC(NULL_VALUE_ERROR); 80 | } 81 | 82 | mqttInitParams.enableAutoReconnect = pParams->enableAutoReconnect; 83 | mqttInitParams.pHostURL = pParams->pHost; 84 | mqttInitParams.port = pParams->port; 85 | mqttInitParams.pRootCALocation = pParams->pRootCA; 86 | mqttInitParams.pDeviceCertLocation = pParams->pClientCRT; 87 | mqttInitParams.pDevicePrivateKeyLocation = pParams->pClientKey; 88 | mqttInitParams.mqttPacketTimeout_ms = 5000; 89 | mqttInitParams.mqttCommandTimeout_ms = 20000; 90 | mqttInitParams.tlsHandshakeTimeout_ms = 5000; 91 | mqttInitParams.isSSLHostnameVerify = true; 92 | mqttInitParams.disconnectHandler = pParams->disconnectHandler; 93 | 94 | rc = aws_iot_mqtt_init(pClient, &mqttInitParams); 95 | if(SUCCESS != rc) { 96 | FUNC_EXIT_RC(rc); 97 | } 98 | 99 | resetClientTokenSequenceNum(); 100 | aws_iot_shadow_reset_last_received_version(); 101 | initDeltaTokens(); 102 | 103 | FUNC_EXIT_RC(SUCCESS); 104 | } 105 | 106 | IoT_Error_t aws_iot_shadow_connect(AWS_IoT_Client *pClient, ShadowConnectParameters_t *pParams) { 107 | IoT_Error_t rc = SUCCESS; 108 | uint16_t deleteAcceptedTopicLen; 109 | IoT_Client_Connect_Params ConnectParams = iotClientConnectParamsDefault; 110 | 111 | FUNC_ENTRY; 112 | 113 | if(NULL == pClient || NULL == pParams || NULL == pParams->pMqttClientId) { 114 | FUNC_EXIT_RC(NULL_VALUE_ERROR); 115 | } 116 | 117 | snprintf(myThingName, MAX_SIZE_OF_THING_NAME, "%s", pParams->pMyThingName); 118 | snprintf(mqttClientID, MAX_SIZE_OF_UNIQUE_CLIENT_ID_BYTES, "%s", pParams->pMqttClientId); 119 | 120 | ConnectParams.keepAliveIntervalInSec = 600; // NOTE: Temporary fix 121 | ConnectParams.MQTTVersion = MQTT_3_1_1; 122 | ConnectParams.isCleanSession = true; 123 | ConnectParams.isWillMsgPresent = false; 124 | ConnectParams.pClientID = pParams->pMqttClientId; 125 | ConnectParams.clientIDLen = pParams->mqttClientIdLen; 126 | ConnectParams.pPassword = NULL; 127 | ConnectParams.pUsername = NULL; 128 | 129 | rc = aws_iot_mqtt_connect(pClient, &ConnectParams); 130 | 131 | if(SUCCESS != rc) { 132 | FUNC_EXIT_RC(rc); 133 | } 134 | 135 | initializeRecords(pClient); 136 | 137 | if(NULL != pParams->deleteActionHandler) { 138 | snprintf(deleteAcceptedTopic, MAX_SHADOW_TOPIC_LENGTH_BYTES, 139 | "$aws/things/%s/shadow/delete/accepted", myThingName); 140 | deleteAcceptedTopicLen = (uint16_t) strlen(deleteAcceptedTopic); 141 | rc = aws_iot_mqtt_subscribe(pClient, deleteAcceptedTopic, deleteAcceptedTopicLen, QOS1, 142 | pParams->deleteActionHandler, (void *) myThingName); 143 | } 144 | 145 | FUNC_EXIT_RC(rc); 146 | } 147 | 148 | IoT_Error_t aws_iot_shadow_register_delta(AWS_IoT_Client *pMqttClient, jsonStruct_t *pStruct) { 149 | if(NULL == pMqttClient || NULL == pStruct) { 150 | return NULL_VALUE_ERROR; 151 | } 152 | 153 | if(!aws_iot_mqtt_is_client_connected(pMqttClient)) { 154 | return MQTT_CONNECTION_ERROR; 155 | } 156 | 157 | return registerJsonTokenOnDelta(pStruct); 158 | } 159 | 160 | IoT_Error_t aws_iot_shadow_yield(AWS_IoT_Client *pClient, uint32_t timeout) { 161 | if(NULL == pClient) { 162 | return NULL_VALUE_ERROR; 163 | } 164 | 165 | HandleExpiredResponseCallbacks(); 166 | return aws_iot_mqtt_yield(pClient, timeout); 167 | } 168 | 169 | IoT_Error_t aws_iot_shadow_disconnect(AWS_IoT_Client *pClient) { 170 | return aws_iot_mqtt_disconnect(pClient); 171 | } 172 | 173 | IoT_Error_t aws_iot_shadow_update(AWS_IoT_Client *pClient, const char *pThingName, char *pJsonString, 174 | fpActionCallback_t callback, void *pContextData, uint8_t timeout_seconds, 175 | bool isPersistentSubscribe) { 176 | IoT_Error_t rc; 177 | 178 | if(NULL == pClient) { 179 | FUNC_EXIT_RC(NULL_VALUE_ERROR); 180 | } 181 | 182 | if(!aws_iot_mqtt_is_client_connected(pClient)) { 183 | FUNC_EXIT_RC(MQTT_CONNECTION_ERROR); 184 | } 185 | 186 | rc = aws_iot_shadow_internal_action(pThingName, SHADOW_UPDATE, pJsonString, strlen(pJsonString), callback, pContextData, 187 | timeout_seconds, isPersistentSubscribe); 188 | 189 | FUNC_EXIT_RC(rc); 190 | } 191 | 192 | IoT_Error_t aws_iot_shadow_delete(AWS_IoT_Client *pClient, const char *pThingName, fpActionCallback_t callback, 193 | void *pContextData, uint8_t timeout_seconds, bool isPersistentSubscribe) { 194 | char deleteRequestJsonBuf[MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE]; 195 | IoT_Error_t rc; 196 | 197 | FUNC_ENTRY; 198 | 199 | if(NULL == pClient) { 200 | FUNC_EXIT_RC(NULL_VALUE_ERROR); 201 | } 202 | 203 | if(!aws_iot_mqtt_is_client_connected(pClient)) { 204 | FUNC_EXIT_RC(MQTT_CONNECTION_ERROR); 205 | } 206 | 207 | rc = aws_iot_shadow_internal_delete_request_json(deleteRequestJsonBuf, MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE ); 208 | if ( SUCCESS != rc ) { 209 | FUNC_EXIT_RC( rc ); 210 | } 211 | 212 | rc = aws_iot_shadow_internal_action(pThingName, SHADOW_DELETE, deleteRequestJsonBuf, MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE, callback, pContextData, 213 | timeout_seconds, isPersistentSubscribe); 214 | 215 | FUNC_EXIT_RC(rc); 216 | } 217 | 218 | IoT_Error_t aws_iot_shadow_get(AWS_IoT_Client *pClient, const char *pThingName, fpActionCallback_t callback, 219 | void *pContextData, uint8_t timeout_seconds, bool isPersistentSubscribe) { 220 | char getRequestJsonBuf[MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE]; 221 | IoT_Error_t rc; 222 | 223 | FUNC_ENTRY; 224 | 225 | if(NULL == pClient) { 226 | FUNC_EXIT_RC(NULL_VALUE_ERROR); 227 | } 228 | 229 | if(!aws_iot_mqtt_is_client_connected(pClient)) { 230 | FUNC_EXIT_RC(MQTT_CONNECTION_ERROR); 231 | } 232 | 233 | rc = aws_iot_shadow_internal_get_request_json(getRequestJsonBuf, MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE ); 234 | if (SUCCESS != rc) { 235 | FUNC_EXIT_RC(rc); 236 | } 237 | 238 | rc = aws_iot_shadow_internal_action(pThingName, SHADOW_GET, getRequestJsonBuf, MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE, callback, pContextData, 239 | timeout_seconds, isPersistentSubscribe); 240 | FUNC_EXIT_RC(rc); 241 | } 242 | 243 | IoT_Error_t aws_iot_shadow_set_autoreconnect_status(AWS_IoT_Client *pClient, bool newStatus) { 244 | return aws_iot_mqtt_autoreconnect_set_status(pClient, newStatus); 245 | } 246 | 247 | #ifdef __cplusplus 248 | } 249 | #endif 250 | 251 | -------------------------------------------------------------------------------- /src/aws_iot_mqtt_client_interface.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | // Based on Eclipse Paho. 17 | /******************************************************************************* 18 | * Copyright (c) 2014 IBM Corp. 19 | * 20 | * All rights reserved. This program and the accompanying materials 21 | * are made available under the terms of the Eclipse Public License v1.0 22 | * and Eclipse Distribution License v1.0 which accompany this distribution. 23 | * 24 | * The Eclipse Public License is available at 25 | * http://www.eclipse.org/legal/epl-v10.html 26 | * and the Eclipse Distribution License is available at 27 | * http://www.eclipse.org/org/documents/edl-v10.php. 28 | * 29 | * Contributors: 30 | * Ian Craggs - initial API and implementation and/or initial documentation 31 | * Xiang Rong - 442039 Add makefile to Embedded C client 32 | *******************************************************************************/ 33 | 34 | /** 35 | * @file aws_iot_mqtt_interface.h 36 | * @brief Interface definition for MQTT client. 37 | */ 38 | 39 | #ifndef AWS_IOT_SDK_SRC_IOT_MQTT_INTERFACE_H 40 | #define AWS_IOT_SDK_SRC_IOT_MQTT_INTERFACE_H 41 | 42 | #ifdef __cplusplus 43 | extern "C" { 44 | #endif 45 | 46 | /* Library Header files */ 47 | #include "stdio.h" 48 | #include "stdbool.h" 49 | #include "stdint.h" 50 | #include "stddef.h" 51 | 52 | /* AWS Specific header files */ 53 | #include "aws_iot_error.h" 54 | #include "aws_iot_config.h" 55 | #include "aws_iot_mqtt_client.h" 56 | 57 | /* Platform specific implementation header files */ 58 | #include "network_interface.h" 59 | #include "timer_interface.h" 60 | 61 | 62 | /** 63 | * @brief Clean mqtt client from all dynamic memory allocate 64 | * 65 | * This function will free up memory that was dynamically allocated for the client. 66 | * 67 | * @param pClient MQTT Client that was previously created by calling aws_iot_mqtt_init 68 | * @return An IoT Error Type defining successful/failed freeing 69 | */ 70 | IoT_Error_t aws_iot_mqtt_free( AWS_IoT_Client *pClient ); 71 | 72 | /** 73 | * @brief MQTT Client Initialization Function 74 | * 75 | * Called to initialize the MQTT Client 76 | * 77 | * @param pClient Reference to the IoT Client 78 | * @param pInitParams Pointer to MQTT connection parameters 79 | * 80 | * @return IoT_Error_t Type defining successful/failed API call 81 | */ 82 | IoT_Error_t aws_iot_mqtt_init(AWS_IoT_Client *pClient, IoT_Client_Init_Params *pInitParams); 83 | 84 | /** 85 | * @brief MQTT Connection Function 86 | * 87 | * Called to establish an MQTT connection with the AWS IoT Service 88 | * 89 | * @param pClient Reference to the IoT Client 90 | * @param pConnectParams Pointer to MQTT connection parameters 91 | * 92 | * @return An IoT Error Type defining successful/failed connection 93 | */ 94 | IoT_Error_t aws_iot_mqtt_connect(AWS_IoT_Client *pClient, IoT_Client_Connect_Params *pConnectParams); 95 | 96 | /** 97 | * @brief Publish an MQTT message on a topic 98 | * 99 | * Called to publish an MQTT message on a topic. 100 | * @note Call is blocking. In the case of a QoS 0 message the function returns 101 | * after the message was successfully passed to the TLS layer. In the case of QoS 1 102 | * the function returns after the receipt of the PUBACK control packet. 103 | * 104 | * @param pClient Reference to the IoT Client 105 | * @param pTopicName Topic Name to publish to 106 | * @param topicNameLen Length of the topic name 107 | * @param pParams Pointer to Publish Message parameters 108 | * 109 | * @return An IoT Error Type defining successful/failed publish 110 | */ 111 | IoT_Error_t aws_iot_mqtt_publish(AWS_IoT_Client *pClient, const char *pTopicName, uint16_t topicNameLen, 112 | IoT_Publish_Message_Params *pParams); 113 | 114 | /** 115 | * @brief Subscribe to an MQTT topic. 116 | * 117 | * Called to send a subscribe message to the broker requesting a subscription 118 | * to an MQTT topic. 119 | * @note Call is blocking. The call returns after the receipt of the SUBACK control packet. 120 | * @warning pTopicName and pApplicationHandlerData need to be static in memory. 121 | * 122 | * @param pClient Reference to the IoT Client 123 | * @param pTopicName Topic Name to publish to. pTopicName needs to be static in memory since 124 | * no malloc are performed by the SDK 125 | * @param topicNameLen Length of the topic name 126 | * @param pApplicationHandler_t Reference to the handler function for this subscription 127 | * @param pApplicationHandlerData Point to data passed to the callback. 128 | * pApplicationHandlerData also needs to be static in memory since no malloc are performed by the SDK 129 | * 130 | * @return An IoT Error Type defining successful/failed subscription 131 | */ 132 | IoT_Error_t aws_iot_mqtt_subscribe(AWS_IoT_Client *pClient, const char *pTopicName, uint16_t topicNameLen, 133 | QoS qos, pApplicationHandler_t pApplicationHandler, void *pApplicationHandlerData); 134 | 135 | /** 136 | * @brief Subscribe to an MQTT topic. 137 | * 138 | * Called to resubscribe to the topics that the client has active subscriptions on. 139 | * Internally called when autoreconnect is enabled 140 | * 141 | * @note Call is blocking. The call returns after the receipt of the SUBACK control packet. 142 | * 143 | * @param pClient Reference to the IoT Client 144 | * 145 | * @return An IoT Error Type defining successful/failed subscription 146 | */ 147 | IoT_Error_t aws_iot_mqtt_resubscribe(AWS_IoT_Client *pClient); 148 | 149 | /** 150 | * @brief Unsubscribe to an MQTT topic. 151 | * 152 | * Called to send an unsubscribe message to the broker requesting removal of a subscription 153 | * to an MQTT topic. 154 | * @note Call is blocking. The call returns after the receipt of the UNSUBACK control packet. 155 | * 156 | * @param pClient Reference to the IoT Client 157 | * @param pTopicName Topic Name to publish to 158 | * @param topicNameLen Length of the topic name 159 | * 160 | * @return An IoT Error Type defining successful/failed unsubscribe call 161 | */ 162 | IoT_Error_t aws_iot_mqtt_unsubscribe(AWS_IoT_Client *pClient, const char *pTopicFilter, uint16_t topicFilterLen); 163 | 164 | /** 165 | * @brief Disconnect an MQTT Connection 166 | * 167 | * Called to send a disconnect message to the broker. 168 | * 169 | * @param pClient Reference to the IoT Client 170 | * 171 | * @return An IoT Error Type defining successful/failed send of the disconnect control packet. 172 | */ 173 | IoT_Error_t aws_iot_mqtt_disconnect(AWS_IoT_Client *pClient); 174 | 175 | /** 176 | * @brief Yield to the MQTT client 177 | * 178 | * Called to yield the current thread to the underlying MQTT client. This time is used by 179 | * the MQTT client to manage PING requests to monitor the health of the TCP connection as 180 | * well as periodically check the socket receive buffer for subscribe messages. Yield() 181 | * must be called at a rate faster than the keepalive interval. It must also be called 182 | * at a rate faster than the incoming message rate as this is the only way the client receives 183 | * processing time to manage incoming messages. 184 | * 185 | * @param pClient Reference to the IoT Client 186 | * @param timeout_ms Maximum number of milliseconds to pass thread execution to the client. 187 | * 188 | * @return An IoT Error Type defining successful/failed client processing. 189 | * If this call results in an error it is likely the MQTT connection has dropped. 190 | * iot_is_mqtt_connected can be called to confirm. 191 | */ 192 | IoT_Error_t aws_iot_mqtt_yield(AWS_IoT_Client *pClient, uint32_t timeout_ms); 193 | 194 | /** 195 | * @brief MQTT Manual Re-Connection Function 196 | * 197 | * Called to establish an MQTT connection with the AWS IoT Service 198 | * using parameters from the last time a connection was attempted 199 | * Use after disconnect to start the reconnect process manually 200 | * Makes only one reconnect attempt Sets the client state to 201 | * pending reconnect in case of failure 202 | * 203 | * @param pClient Reference to the IoT Client 204 | * 205 | * @return An IoT Error Type defining successful/failed connection 206 | */ 207 | IoT_Error_t aws_iot_mqtt_attempt_reconnect(AWS_IoT_Client *pClient); 208 | 209 | #ifdef __cplusplus 210 | } 211 | #endif 212 | 213 | #endif 214 | -------------------------------------------------------------------------------- /src/AWS_IOT.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | ExploreEmbedded Copyright Notice 3 | **************************************************************************************************** 4 | * File: AWS_IOT.cpp 5 | * Version: 1.0 6 | * Author: ExploreEmbedded 7 | * Website: http://www.exploreembedded.com/wiki 8 | * Description: ESP32 Arduino library for AWS IOT. 9 | 10 | This code has been developed and tested on ExploreEmbedded boards. 11 | We strongly believe that the library works on any of development boards for respective controllers. 12 | Check this link http://www.exploreembedded.com/wiki for awesome tutorials on 8051,PIC,AVR,ARM,Robotics,RTOS,IOT. 13 | ExploreEmbedded invests substantial time and effort developing open source HW and SW tools, to support consider buying the ExploreEmbedded boards. 14 | 15 | The ExploreEmbedded libraries and examples are licensed under the terms of the new-bsd license(two-clause bsd license). 16 | See also: http://www.opensource.org/licenses/bsd-license.php 17 | 18 | EXPLOREEMBEDDED DISCLAIMS ANY KIND OF HARDWARE FAILURE RESULTING OUT OF USAGE OF LIBRARIES, DIRECTLY OR 19 | INDIRECTLY. FILES MAY BE SUBJECT TO CHANGE WITHOUT PRIOR NOTICE. THE REVISION HISTORY CONTAINS THE INFORMATION 20 | RELATED TO UPDATES. 21 | 22 | 23 | Permission to use, copy, modify, and distribute this software and its documentation for any purpose 24 | and without fee is hereby granted, provided that this copyright notices appear in all copies 25 | and that both those copyright notices and this permission notice appear in supporting documentation. 26 | **************************************************************************************************/ 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "AWS_IOT.h" 35 | #include "aws_iot_config.h" 36 | #include "aws_iot_log.h" 37 | #include "aws_iot_version.h" 38 | 39 | #include "aws_iot_mqtt_client.h" 40 | #include "aws_iot_mqtt_client_interface.h" 41 | 42 | 43 | #include "freertos/FreeRTOS.h" 44 | #include "freertos/task.h" 45 | #include "freertos/event_groups.h" 46 | #include "esp_system.h" 47 | #include "esp_wifi.h" 48 | #include "esp_event_loop.h" 49 | #include "esp_log.h" 50 | #include "esp_vfs_fat.h" 51 | #include "driver/sdmmc_host.h" 52 | 53 | 54 | 55 | static const char *TAG = "AWS_IOT"; 56 | char AWS_IOT_HOST_ADDRESS[128]; 57 | 58 | AWS_IoT_Client client; 59 | IoT_Publish_Message_Params paramsQOS0; 60 | pSubCallBackHandler_t subApplCallBackHandler = 0; 61 | 62 | void aws_iot_task(void *param); 63 | 64 | void iot_subscribe_callback_handler(AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen, 65 | IoT_Publish_Message_Params *params, void *pData) 66 | { 67 | if(subApplCallBackHandler != 0) //User call back if configured 68 | subApplCallBackHandler(topicName,params->payloadLen,(char *)params->payload); 69 | } 70 | 71 | 72 | 73 | void disconnectCallbackHandler(AWS_IoT_Client *pClient, void *data) 74 | { 75 | ESP_LOGW(TAG, "MQTT Disconnect"); 76 | IoT_Error_t rc = FAILURE; 77 | 78 | if(!pClient) 79 | { 80 | return; 81 | } 82 | 83 | if(aws_iot_is_autoreconnect_enabled(pClient)) { 84 | ESP_LOGI(TAG, "Auto Reconnect is enabled, Reconnecting attempt will start now"); 85 | } 86 | else 87 | { 88 | ESP_LOGW(TAG, "Auto Reconnect not enabled. Starting manual reconnect..."); 89 | // TODO - was commented out - check 90 | rc = aws_iot_mqtt_attempt_reconnect(pClient); 91 | if(NETWORK_RECONNECTED == rc) { 92 | ESP_LOGW(TAG, "Manual Reconnect Successful"); 93 | } 94 | else { 95 | ESP_LOGW(TAG, "Manual Reconnect Failed - %d", rc); 96 | } 97 | } 98 | } 99 | 100 | 101 | int AWS_IOT::connect(const char *hostAddress, const char *clientID, 102 | const char *aws_root_ca_pem, 103 | const char *certificate_pem_crt, 104 | const char *private_pem_key) { 105 | const size_t stack_size = 36*1024; 106 | 107 | strcpy(AWS_IOT_HOST_ADDRESS,hostAddress); 108 | IoT_Error_t rc = FAILURE; 109 | 110 | 111 | IoT_Client_Init_Params mqttInitParams = iotClientInitParamsDefault; 112 | IoT_Client_Connect_Params connectParams = iotClientConnectParamsDefault; 113 | 114 | 115 | ESP_LOGI(TAG, "AWS IoT SDK Version %d.%d.%d-%s", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_TAG); 116 | 117 | mqttInitParams.enableAutoReconnect = false; // We enable this later below 118 | mqttInitParams.pHostURL = AWS_IOT_HOST_ADDRESS; 119 | mqttInitParams.port = CONFIG_AWS_IOT_MQTT_PORT; 120 | 121 | 122 | mqttInitParams.pRootCALocation = const_cast(aws_root_ca_pem); 123 | mqttInitParams.pDeviceCertLocation = const_cast(certificate_pem_crt); 124 | mqttInitParams.pDevicePrivateKeyLocation = const_cast(private_pem_key); 125 | 126 | 127 | mqttInitParams.mqttCommandTimeout_ms = 20000; 128 | mqttInitParams.tlsHandshakeTimeout_ms = 5000; 129 | mqttInitParams.isSSLHostnameVerify = true; 130 | mqttInitParams.disconnectHandler = disconnectCallbackHandler; 131 | mqttInitParams.disconnectHandlerData = nullptr; 132 | 133 | 134 | rc = aws_iot_mqtt_init(&client, &mqttInitParams); 135 | 136 | if(SUCCESS != rc) { 137 | ESP_LOGE(TAG, "aws_iot_mqtt_init returned error : %d ", rc); 138 | return rc; //abort(); 139 | } 140 | 141 | connectParams.keepAliveIntervalInSec = 10; 142 | connectParams.isCleanSession = true; 143 | connectParams.MQTTVersion = MQTT_3_1_1; 144 | /* Client ID is set in the menuconfig of the example */ 145 | connectParams.pClientID = const_cast(clientID); 146 | connectParams.clientIDLen = (uint16_t) strlen(clientID); 147 | connectParams.isWillMsgPresent = false; 148 | 149 | ESP_LOGI(TAG, "Connecting to AWS..."); 150 | 151 | do { 152 | rc = aws_iot_mqtt_connect(&client, &connectParams); 153 | 154 | if(SUCCESS != rc) { 155 | ESP_LOGE(TAG, "Error(%d) connecting to %s:%d, \n\rTrying to reconnect", rc, mqttInitParams.pHostURL, mqttInitParams.port); 156 | 157 | } 158 | 159 | } while(SUCCESS != rc); 160 | 161 | 162 | /* 163 | * Enable Auto Reconnect functionality. Minimum and Maximum time of Exponential backoff are set in aws_iot_config.h 164 | * #AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL 165 | * #AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL 166 | */ 167 | // TODO - bock was commented out - check 168 | rc = aws_iot_mqtt_autoreconnect_set_status(&client, true); 169 | if(SUCCESS != rc) { 170 | ESP_LOGE(TAG, "Unable to set Auto Reconnect to true - %d", rc); 171 | abort(); 172 | } 173 | 174 | if(rc == SUCCESS) 175 | xTaskCreatePinnedToCore(&aws_iot_task, "aws_iot_task", stack_size, nullptr, 5, nullptr, 1); 176 | 177 | return rc; 178 | } 179 | 180 | 181 | int AWS_IOT::publish(const char *pubtopic,const char *pubPayLoad) 182 | { 183 | IoT_Error_t rc; 184 | 185 | paramsQOS0.qos = QOS0; 186 | paramsQOS0.payload = const_cast(pubPayLoad); 187 | paramsQOS0.isRetained = 0; 188 | 189 | paramsQOS0.payloadLen = strlen(pubPayLoad); 190 | rc = aws_iot_mqtt_publish(&client, pubtopic, strlen(pubtopic), ¶msQOS0); 191 | 192 | return rc; 193 | } 194 | 195 | 196 | 197 | int AWS_IOT::subscribe(const char *subTopic, pSubCallBackHandler_t pSubCallBackHandler) 198 | { 199 | IoT_Error_t rc; 200 | 201 | subApplCallBackHandler = pSubCallBackHandler; 202 | 203 | ESP_LOGI(TAG, "Subscribing..."); 204 | rc = aws_iot_mqtt_subscribe(&client, subTopic, strlen(subTopic), QOS0, iot_subscribe_callback_handler, nullptr); 205 | if(SUCCESS != rc) { 206 | ESP_LOGE(TAG, "Error subscribing : %d ", rc); 207 | return rc; 208 | } 209 | ESP_LOGI(TAG, "Subscribing... Successful"); 210 | 211 | return rc; 212 | } 213 | 214 | 215 | 216 | 217 | void aws_iot_task(void *param) { 218 | 219 | IoT_Error_t rc = SUCCESS; 220 | 221 | while(1) 222 | { 223 | //Max time the yield function will wait for read messages 224 | rc = aws_iot_mqtt_yield(&client, /*200*/ 5); 225 | 226 | if(NETWORK_ATTEMPTING_RECONNECT == rc) 227 | { 228 | // If the client is attempting to reconnect we will skip the rest of the loop. 229 | continue; 230 | } 231 | 232 | 233 | vTaskDelay(/*1000*/ 550 / portTICK_RATE_MS); 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /src/aws_iot_mqtt_client_unsubscribe.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | // Based on Eclipse Paho. 17 | /******************************************************************************* 18 | * Copyright (c) 2014 IBM Corp. 19 | * 20 | * All rights reserved. This program and the accompanying materials 21 | * are made available under the terms of the Eclipse Public License v1.0 22 | * and Eclipse Distribution License v1.0 which accompany this distribution. 23 | * 24 | * The Eclipse Public License is available at 25 | * http://www.eclipse.org/legal/epl-v10.html 26 | * and the Eclipse Distribution License is available at 27 | * http://www.eclipse.org/org/documents/edl-v10.php. 28 | * 29 | * Contributors: 30 | * Ian Craggs - initial API and implementation and/or initial documentation 31 | *******************************************************************************/ 32 | 33 | /** 34 | * @file aws_iot_mqtt_client_unsubscribe.c 35 | * @brief MQTT client unsubscribe API definitions 36 | */ 37 | 38 | #ifdef __cplusplus 39 | extern "C" { 40 | #endif 41 | 42 | #include "aws_iot_mqtt_client_common_internal.h" 43 | 44 | /** 45 | * Serializes the supplied unsubscribe data into the supplied buffer, ready for sending 46 | * @param pTxBuf the raw buffer data, of the correct length determined by the remaining length field 47 | * @param txBufLen the length in bytes of the data in the supplied buffer 48 | * @param dup integer - the MQTT dup flag 49 | * @param packetId integer - the MQTT packet identifier 50 | * @param count - number of members in the topicFilters array 51 | * @param pTopicNameList - array of topic filter names 52 | * @param pTopicNameLenList - array of length of topic filter names in pTopicNameList 53 | * @param pSerializedLen - the length of the serialized data 54 | * @return IoT_Error_t indicating function execution status 55 | */ 56 | static IoT_Error_t _aws_iot_mqtt_serialize_unsubscribe(unsigned char *pTxBuf, size_t txBufLen, 57 | uint8_t dup, uint16_t packetId, 58 | uint32_t count, const char **pTopicNameList, 59 | uint16_t *pTopicNameLenList, uint32_t *pSerializedLen) { 60 | unsigned char *ptr = pTxBuf; 61 | uint32_t i = 0; 62 | uint32_t rem_len = 2; /* packetId */ 63 | IoT_Error_t rc; 64 | MQTTHeader header = {0}; 65 | 66 | FUNC_ENTRY; 67 | 68 | for(i = 0; i < count; ++i) { 69 | rem_len += (uint32_t) (pTopicNameLenList[i] + 2); /* topic + length */ 70 | } 71 | 72 | if(aws_iot_mqtt_internal_get_final_packet_length_from_remaining_length(rem_len) > txBufLen) { 73 | FUNC_EXIT_RC(MQTT_TX_BUFFER_TOO_SHORT_ERROR); 74 | } 75 | 76 | rc = aws_iot_mqtt_internal_init_header(&header, UNSUBSCRIBE, QOS1, dup, 0); 77 | if(SUCCESS != rc) { 78 | FUNC_EXIT_RC(rc); 79 | } 80 | aws_iot_mqtt_internal_write_char(&ptr, header.byte); /* write header */ 81 | 82 | ptr += aws_iot_mqtt_internal_write_len_to_buffer(ptr, rem_len); /* write remaining length */ 83 | 84 | aws_iot_mqtt_internal_write_uint_16(&ptr, packetId); 85 | 86 | for(i = 0; i < count; ++i) { 87 | aws_iot_mqtt_internal_write_utf8_string(&ptr, pTopicNameList[i], pTopicNameLenList[i]); 88 | } 89 | 90 | *pSerializedLen = (uint32_t) (ptr - pTxBuf); 91 | 92 | FUNC_EXIT_RC(SUCCESS); 93 | } 94 | 95 | 96 | /** 97 | * Deserializes the supplied (wire) buffer into unsuback data 98 | * @param pPacketId returned integer - the MQTT packet identifier 99 | * @param pRxBuf the raw buffer data, of the correct length determined by the remaining length field 100 | * @param rxBufLen the length in bytes of the data in the supplied buffer 101 | * @return IoT_Error_t indicating function execution status 102 | */ 103 | static IoT_Error_t _aws_iot_mqtt_deserialize_unsuback(uint16_t *pPacketId, unsigned char *pRxBuf, size_t rxBufLen) { 104 | unsigned char type = 0; 105 | unsigned char dup = 0; 106 | IoT_Error_t rc; 107 | 108 | FUNC_ENTRY; 109 | 110 | rc = aws_iot_mqtt_internal_deserialize_ack(&type, &dup, pPacketId, pRxBuf, rxBufLen); 111 | if(SUCCESS == rc && UNSUBACK != type) { 112 | rc = FAILURE; 113 | } 114 | 115 | FUNC_EXIT_RC(rc); 116 | } 117 | 118 | /** 119 | * @brief Unsubscribe to an MQTT topic. 120 | * 121 | * Called to send an unsubscribe message to the broker requesting removal of a subscription 122 | * to an MQTT topic. 123 | * @note Call is blocking. The call returns after the receipt of the UNSUBACK control packet. 124 | * This is the internal function which is called by the unsubscribe API to perform the operation. 125 | * Not meant to be called directly as it doesn't do validations or client state changes 126 | * 127 | * @param pClient Reference to the IoT Client 128 | * @param pTopicName Topic Name to publish to 129 | * @param topicNameLen Length of the topic name 130 | * 131 | * @return An IoT Error Type defining successful/failed unsubscribe call 132 | */ 133 | static IoT_Error_t _aws_iot_mqtt_internal_unsubscribe(AWS_IoT_Client *pClient, const char *pTopicFilter, 134 | uint16_t topicFilterLen) { 135 | /* No NULL checks because this is a static internal function */ 136 | 137 | Timer timer; 138 | 139 | uint16_t packet_id; 140 | uint32_t serializedLen = 0; 141 | uint32_t i = 0; 142 | IoT_Error_t rc; 143 | bool subscriptionExists = false; 144 | 145 | FUNC_ENTRY; 146 | 147 | /* Remove from message handler array */ 148 | for(i = 0; i < AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS; ++i) { 149 | if(pClient->clientData.messageHandlers[i].topicName != NULL && 150 | (strcmp(pClient->clientData.messageHandlers[i].topicName, pTopicFilter) == 0)) { 151 | subscriptionExists = true; 152 | break; 153 | } 154 | } 155 | 156 | if(false == subscriptionExists) { 157 | FUNC_EXIT_RC(FAILURE); 158 | } 159 | 160 | init_timer(&timer); 161 | countdown_ms(&timer, pClient->clientData.commandTimeoutMs); 162 | 163 | rc = _aws_iot_mqtt_serialize_unsubscribe(pClient->clientData.writeBuf, pClient->clientData.writeBufSize, 0, 164 | aws_iot_mqtt_get_next_packet_id(pClient), 1, &pTopicFilter, 165 | &topicFilterLen, &serializedLen); 166 | if(SUCCESS != rc) { 167 | FUNC_EXIT_RC(rc); 168 | } 169 | 170 | /* send the unsubscribe packet */ 171 | rc = aws_iot_mqtt_internal_send_packet(pClient, serializedLen, &timer); 172 | if(SUCCESS != rc) { 173 | FUNC_EXIT_RC(rc); 174 | } 175 | 176 | rc = aws_iot_mqtt_internal_wait_for_read(pClient, UNSUBACK, &timer); 177 | if(SUCCESS != rc) { 178 | FUNC_EXIT_RC(rc); 179 | } 180 | 181 | rc = _aws_iot_mqtt_deserialize_unsuback(&packet_id, pClient->clientData.readBuf, pClient->clientData.readBufSize); 182 | if(SUCCESS != rc) { 183 | FUNC_EXIT_RC(rc); 184 | } 185 | 186 | /* Remove from message handler array */ 187 | for(i = 0; i < AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS; ++i) { 188 | if(pClient->clientData.messageHandlers[i].topicName != NULL && 189 | (strcmp(pClient->clientData.messageHandlers[i].topicName, pTopicFilter) == 0)) { 190 | pClient->clientData.messageHandlers[i].topicName = NULL; 191 | /* We don't want to break here, in case the same topic is registered 192 | * with 2 callbacks. Unlikely scenario */ 193 | } 194 | } 195 | 196 | FUNC_EXIT_RC(SUCCESS); 197 | } 198 | 199 | /** 200 | * @brief Unsubscribe to an MQTT topic. 201 | * 202 | * Called to send an unsubscribe message to the broker requesting removal of a subscription 203 | * to an MQTT topic. 204 | * @note Call is blocking. The call returns after the receipt of the UNSUBACK control packet. 205 | * This is the outer function which does the validations and calls the internal unsubscribe above 206 | * to perform the actual operation. It is also responsible for client state changes 207 | * 208 | * @param pClient Reference to the IoT Client 209 | * @param pTopicName Topic Name to publish to 210 | * @param topicNameLen Length of the topic name 211 | * 212 | * @return An IoT Error Type defining successful/failed unsubscribe call 213 | */ 214 | IoT_Error_t aws_iot_mqtt_unsubscribe(AWS_IoT_Client *pClient, const char *pTopicFilter, uint16_t topicFilterLen) { 215 | IoT_Error_t rc, unsubRc; 216 | ClientState clientState; 217 | 218 | if(NULL == pClient || NULL == pTopicFilter) { 219 | return NULL_VALUE_ERROR; 220 | } 221 | 222 | if(!aws_iot_mqtt_is_client_connected(pClient)) { 223 | return NETWORK_DISCONNECTED_ERROR; 224 | } 225 | 226 | clientState = aws_iot_mqtt_get_client_state(pClient); 227 | if(CLIENT_STATE_CONNECTED_IDLE != clientState && CLIENT_STATE_CONNECTED_WAIT_FOR_CB_RETURN != clientState) { 228 | return MQTT_CLIENT_NOT_IDLE_ERROR; 229 | } 230 | 231 | rc = aws_iot_mqtt_set_client_state(pClient, clientState, CLIENT_STATE_CONNECTED_UNSUBSCRIBE_IN_PROGRESS); 232 | if(SUCCESS != rc) { 233 | rc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTED_UNSUBSCRIBE_IN_PROGRESS, clientState); 234 | return rc; 235 | } 236 | 237 | unsubRc = _aws_iot_mqtt_internal_unsubscribe(pClient, pTopicFilter, topicFilterLen); 238 | 239 | rc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTED_UNSUBSCRIBE_IN_PROGRESS, clientState); 240 | if(SUCCESS == unsubRc && SUCCESS != rc) { 241 | unsubRc = rc; 242 | } 243 | 244 | return unsubRc; 245 | } 246 | 247 | #ifdef __cplusplus 248 | } 249 | #endif 250 | 251 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESP32 AWS IoT example using Arduino SDK 2 | 3 | ![Build Status](https://github.com/jandelgado/esp32-aws-iot/workflows/run%20tests/badge.svg) 4 | 5 | This is a fork of https://github.com/ExploreEmbedded/Hornbill-Examples 6 | focusing on the AWS_IOT library and removing everything else. The code was 7 | also upgraded to AWS IoT Device SDK v3.0.1. 8 | 9 | The library was modified so that the TLS configuration (i.e. certificates and 10 | stuff) is _no longer_ included in the library code self, but is now passed to 11 | the `AWS_IOT` class from the client code. This makes the library easier usable. 12 | 13 | * original repository: https://github.com/ExploreEmbedded/Hornbill-Examples 14 | 15 | Additionally, I added a tutorial on using the AWS cli to create everything 16 | needed to set your thing up. 17 | 18 | Also I added [all-in-one thing creator 19 | script](#all-in-one-thing-creator-script) which uses the AWS API (python/boto3) 20 | to create a thing, certificates and attach certificates and policies. In 21 | addition the script outputs ready-to-include C++ code to be included in your 22 | sketch. 23 | 24 | ## Contents 25 | 26 | 27 | 28 | * [Examples](#examples) 29 | * [pubSubTest Example/Quickstart](#pubsubtest-examplequickstart) 30 | * [Build](#build) 31 | * [AWS IoT core notes](#aws-iot-core-notes) 32 | * [Create thing group and thing](#create-thing-group-and-thing) 33 | * [Create keys and certificates](#create-keys-and-certificates) 34 | * [Attach policy to your thing](#attach-policy-to-your-thing) 35 | * [All-in-one thing creator script](#all-in-one-thing-creator-script) 36 | * [MQTT endpoint](#mqtt-endpoint) 37 | * [Troubleshooting](#troubleshooting) 38 | * [Error -0x2780](#error--0x2780) 39 | * [Error -0x2700](#error--0x2700) 40 | * [Author](#author) 41 | 42 | 43 | 44 | ## Examples 45 | 46 | ### pubSubTest Example/Quickstart 47 | 48 | Under [examples/pubSubTest](examples/pubSubTest) the original PubSub example of 49 | the hornbill repository is included, with the configuration externalized to a 50 | separate file [config.h-dist](examples/pubSubTest/config.h-dist). To build the 51 | example, copy the `config.h-dist` file to a file called `config.h` and modify 52 | to fit your configuration: 53 | 54 | * add your WiFi configuration 55 | * add AWS thing private key (see below) 56 | * add AWS thing certificate (see below) 57 | * add [AWS MQTT endpoint address](#mqtt-endpoint) 58 | 59 | The easisiet way to obtain the certificates and create the things is to use 60 | the [all-in-one thing creator script](#all-in-one-thing-creator-script). Don't 61 | forget to create a IAM policy first (see below). 62 | 63 | #### Build 64 | 65 | A plattformio [project](platformio.ini) and [Makefile](Makefile) is provided. 66 | 67 | Run `make upload monitor` to build and upload the example to the ESP32 and 68 | start the serial monitor afterwards to see what is going on. 69 | 70 | If everything works, you should see something like this on your console: 71 | ``` 72 | Attempting to connect to SSID: MYSSID 73 | Connected to wifi 74 | Connected to AWS 75 | Subscribe Successfull 76 | Publish Message:Hello from hornbill ESP32 : 0 77 | Received Message:Hello from hornbill ESP32 : 0 78 | Publish Message:Hello from hornbill ESP32 : 1 79 | Received Message:Hello from hornbill ESP32 : 1 80 | ... 81 | ``` 82 | 83 | ## AWS IoT core notes 84 | 85 | **Work in progress** 86 | 87 | This chapter describes how to use the AWS cli to 88 | 89 | * create a thing type and thing 90 | * create keys and certificates for a thing 91 | * attach a certificate to a thing 92 | * create and attach a policy to a thing 93 | 94 | ### Create thing group and thing 95 | 96 | We use the AWS cli to create a thing type called `ESP32` and a thing with the 97 | name `ESP32_SENSOR`. For convenience and later reference, we store the things 98 | name in the environment variable `THING`. 99 | 100 | ```bash 101 | $ export THING="ESP32_SENSOR" 102 | $ aws iot create-thing-type --thing-type-name "ESP32" 103 | $ aws iot list-thing-types 104 | { 105 | "thingTypes": [ 106 | { 107 | "thingTypeName": "ESP32", 108 | "thingTypeProperties": { 109 | "thingTypeDescription": "ESP32 devices" 110 | }, 111 | "thingTypeMetadata": { 112 | "deprecated": false, 113 | "creationDate": 1530358342.86 114 | }, 115 | "thingTypeArn": "arn:aws:iot:eu-central-1:*****:thingtype/ESP32" 116 | } 117 | ] 118 | } 119 | $ aws iot create-thing --thing-name "$THING" --thing-type-name "ESP32" 120 | $ aws iot list-things 121 | { 122 | "things": [ 123 | { 124 | "thingTypeName": "ESP32", 125 | "thingArn": "arn:aws:iot:eu-central-1:*****:thing/ESP32_SENSOR", 126 | "version": 1, 127 | "thingName": "ESP32_SENSOR", 128 | "attributes": {} 129 | } 130 | ] 131 | } 132 | ``` 133 | 134 | ### Create keys and certificates 135 | 136 | ```bash 137 | $ aws iot create-keys-and-certificate --set-as-active \ 138 | --certificate-pem-outfile="${THING}_cert.pem" \ 139 | --private-key-outfile="${THING}_key.pem" 140 | { 141 | "certificateArn": "arn:aws:iot:eu-central-1:*****:cert/7bb8fd75139186deef4c054a73d15ea9e2a5f603a29025e453057bbe70c767fe", 142 | "certificatePem": "-----BEGIN CERTIFICATE-----\n ... \n-----END CERTIFICATE-----\n", 143 | "keyPair": { 144 | "PublicKey": "-----BEGIN PUBLIC KEY-----\n ... \n-----END PUBLIC KEY-----\n", 145 | "PrivateKey": "-----BEGIN RSA PRIVATE KEY-----\n ... \n-----END RSA PRIVATE KEY-----\n" 146 | }, 147 | "certificateId": "7bb8fd75139186deef4c054a73d15ea9e2a5f603a29025e453057bbe70c767fe" 148 | } 149 | 150 | ``` 151 | 152 | On the thing we later need (see [config.h-dir](examples/pubSubTest/config.h-dist)): 153 | 154 | * the private key stored in `${THING}_key.pem` (i.e. `ESP32_SENSOR_key.pem`) 155 | * the certificate stored in `${THING}_cert.pem` (i.e. `ESP32_SENSOR_cert.pem`) 156 | 157 | Note that this is the only time that the private key will be output by AWS. 158 | 159 | Next we attach the certificate to the thing: 160 | 161 | ```bash 162 | $ aws iot attach-thing-principal --thing-name "$THING" \ 163 | --principal "arn:aws:iot:eu-central-1:*****:cert/7bb8fd75139186deef4c054a73d15ea9e2a5f603a29025e453057bbe70c767fe" 164 | $ aws iot list-principal-things --principal "arn:aws:iot:eu-central-1:*****:cert/7bb8fd75139186deef4c054a73d15ea9e2a5f603a29025e453057bbe70c767fe" 165 | { 166 | "things": [ 167 | "ESP32_SENSOR" 168 | ] 169 | } 170 | aws iot list-thing-principals --thing-name $THING 171 | { 172 | "principals": [ 173 | "arn:aws:iot:eu-central-1:*****:cert/7bb8fd75139186deef4c054a73d15ea9e2a5f603a29025e453057bbe70c767fe" 174 | ] 175 | } 176 | ``` 177 | 178 | ### Attach policy to your thing 179 | 180 | It is important to attach a policy to your thing (technically: to the 181 | certificate attached to the thing), otherwise no communication will be 182 | possible. 183 | 184 | First we need to create a permission named `iot-full-permissions` which, as 185 | the name suggests, has full iot permissions: 186 | 187 | ```bash 188 | $ cat >thing_policy_full_permissions.json< 8883`. 271 | 272 | ## Troubleshooting 273 | 274 | ### Error -0x2780 275 | 276 | ``` 277 | E (15426) aws_iot: failed! mbedtls_x509_crt_parse returned -0x2780 while parsing device cert` 278 | ``` 279 | 280 | Check the format of your PEM key and certificates in `config.h`. 281 | 282 | ### Error -0x2700 283 | 284 | ``` 285 | (11417) aws_iot: failed! mbedtls_ssl_handshake returned -0x2700 286 | E (11417) aws_iot: Unable to verify the server's certificate. 287 | E (11427) AWS_IOT: Error(-4) connecting to **********.iot.eu-central-1.amazonaws.com:8883, 288 | ``` 289 | 290 | Are you using the correct MQTT endpoint (hint use the `ATS` endpoint)? 291 | 292 | ## Author 293 | 294 | Jan Delgado , original work from https://github.com/ExploreEmbedded/Hornbill-Examples. 295 | 296 | -------------------------------------------------------------------------------- /tools/create_thing/poetry.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | category = "dev" 3 | description = "Atomic file writes." 4 | marker = "sys_platform == \"win32\"" 5 | name = "atomicwrites" 6 | optional = false 7 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 8 | version = "1.4.0" 9 | 10 | [[package]] 11 | category = "dev" 12 | description = "Classes Without Boilerplate" 13 | name = "attrs" 14 | optional = false 15 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 16 | version = "19.3.0" 17 | 18 | [package.extras] 19 | azure-pipelines = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "pytest-azurepipelines"] 20 | dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "pre-commit"] 21 | docs = ["sphinx", "zope.interface"] 22 | tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] 23 | 24 | [[package]] 25 | category = "main" 26 | description = "The AWS SDK for Python" 27 | name = "boto3" 28 | optional = false 29 | python-versions = "*" 30 | version = "1.14.23" 31 | 32 | [package.dependencies] 33 | botocore = ">=1.17.23,<1.18.0" 34 | jmespath = ">=0.7.1,<1.0.0" 35 | s3transfer = ">=0.3.0,<0.4.0" 36 | 37 | [[package]] 38 | category = "main" 39 | description = "Low-level, data-driven core of boto 3." 40 | name = "botocore" 41 | optional = false 42 | python-versions = "*" 43 | version = "1.17.23" 44 | 45 | [package.dependencies] 46 | docutils = ">=0.10,<0.16" 47 | jmespath = ">=0.7.1,<1.0.0" 48 | python-dateutil = ">=2.1,<3.0.0" 49 | 50 | [package.dependencies.urllib3] 51 | python = "<3.4.0 || >=3.5.0" 52 | version = ">=1.20,<1.26" 53 | 54 | [[package]] 55 | category = "dev" 56 | description = "Cross-platform colored terminal text." 57 | marker = "sys_platform == \"win32\"" 58 | name = "colorama" 59 | optional = false 60 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 61 | version = "0.4.3" 62 | 63 | [[package]] 64 | category = "main" 65 | description = "Docutils -- Python Documentation Utilities" 66 | name = "docutils" 67 | optional = false 68 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 69 | version = "0.15.2" 70 | 71 | [[package]] 72 | category = "main" 73 | description = "JSON Matching Expressions" 74 | name = "jmespath" 75 | optional = false 76 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 77 | version = "0.10.0" 78 | 79 | [[package]] 80 | category = "dev" 81 | description = "More routines for operating on iterables, beyond itertools" 82 | name = "more-itertools" 83 | optional = false 84 | python-versions = ">=3.5" 85 | version = "8.4.0" 86 | 87 | [[package]] 88 | category = "dev" 89 | description = "Core utilities for Python packages" 90 | name = "packaging" 91 | optional = false 92 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 93 | version = "20.4" 94 | 95 | [package.dependencies] 96 | pyparsing = ">=2.0.2" 97 | six = "*" 98 | 99 | [[package]] 100 | category = "dev" 101 | description = "plugin and hook calling mechanisms for python" 102 | name = "pluggy" 103 | optional = false 104 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 105 | version = "0.13.1" 106 | 107 | [package.extras] 108 | dev = ["pre-commit", "tox"] 109 | 110 | [[package]] 111 | category = "dev" 112 | description = "library with cross-python path, ini-parsing, io, code, log facilities" 113 | name = "py" 114 | optional = false 115 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 116 | version = "1.9.0" 117 | 118 | [[package]] 119 | category = "dev" 120 | description = "Python parsing module" 121 | name = "pyparsing" 122 | optional = false 123 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 124 | version = "2.4.7" 125 | 126 | [[package]] 127 | category = "dev" 128 | description = "pytest: simple powerful testing with Python" 129 | name = "pytest" 130 | optional = false 131 | python-versions = ">=3.5" 132 | version = "5.4.3" 133 | 134 | [package.dependencies] 135 | atomicwrites = ">=1.0" 136 | attrs = ">=17.4.0" 137 | colorama = "*" 138 | more-itertools = ">=4.0.0" 139 | packaging = "*" 140 | pluggy = ">=0.12,<1.0" 141 | py = ">=1.5.0" 142 | wcwidth = "*" 143 | 144 | [package.extras] 145 | checkqa-mypy = ["mypy (v0.761)"] 146 | testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] 147 | 148 | [[package]] 149 | category = "main" 150 | description = "Extensions to the standard Python datetime module" 151 | name = "python-dateutil" 152 | optional = false 153 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" 154 | version = "2.8.1" 155 | 156 | [package.dependencies] 157 | six = ">=1.5" 158 | 159 | [[package]] 160 | category = "main" 161 | description = "An Amazon S3 Transfer Manager" 162 | name = "s3transfer" 163 | optional = false 164 | python-versions = "*" 165 | version = "0.3.3" 166 | 167 | [package.dependencies] 168 | botocore = ">=1.12.36,<2.0a.0" 169 | 170 | [[package]] 171 | category = "main" 172 | description = "Python 2 and 3 compatibility utilities" 173 | name = "six" 174 | optional = false 175 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" 176 | version = "1.15.0" 177 | 178 | [[package]] 179 | category = "main" 180 | description = "HTTP library with thread-safe connection pooling, file post, and more." 181 | marker = "python_version != \"3.4\"" 182 | name = "urllib3" 183 | optional = false 184 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" 185 | version = "1.25.9" 186 | 187 | [package.extras] 188 | brotli = ["brotlipy (>=0.6.0)"] 189 | secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)", "ipaddress"] 190 | socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] 191 | 192 | [[package]] 193 | category = "dev" 194 | description = "Measures the displayed width of unicode strings in a terminal" 195 | name = "wcwidth" 196 | optional = false 197 | python-versions = "*" 198 | version = "0.2.5" 199 | 200 | [metadata] 201 | content-hash = "608b8a24ef773dbe2a0b418440f36e429c229207d101f2029e35034557ec5927" 202 | python-versions = "^3.8" 203 | 204 | [metadata.files] 205 | atomicwrites = [ 206 | {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, 207 | {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, 208 | ] 209 | attrs = [ 210 | {file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"}, 211 | {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"}, 212 | ] 213 | boto3 = [ 214 | {file = "boto3-1.14.23-py2.py3-none-any.whl", hash = "sha256:fd21bb3b15e7ab0525fe0262dc38998f13d15fdf71041d82177f411cb355e858"}, 215 | {file = "boto3-1.14.23.tar.gz", hash = "sha256:a31d9b2d681a0ce7db8e476879222b27455a1cc49a60e2111e0ddb47c574d127"}, 216 | ] 217 | botocore = [ 218 | {file = "botocore-1.17.23-py2.py3-none-any.whl", hash = "sha256:18a0409695fbc707a8f3f2849a93fdc629fda62efe1a5262765fd57b82fbace3"}, 219 | {file = "botocore-1.17.23.tar.gz", hash = "sha256:6711dac304dacb49981d722ef91bd89bd82b6bc68cf0a0890bc30573dcbb1899"}, 220 | ] 221 | colorama = [ 222 | {file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"}, 223 | {file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"}, 224 | ] 225 | docutils = [ 226 | {file = "docutils-0.15.2-py2-none-any.whl", hash = "sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827"}, 227 | {file = "docutils-0.15.2-py3-none-any.whl", hash = "sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0"}, 228 | {file = "docutils-0.15.2.tar.gz", hash = "sha256:a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99"}, 229 | ] 230 | jmespath = [ 231 | {file = "jmespath-0.10.0-py2.py3-none-any.whl", hash = "sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f"}, 232 | {file = "jmespath-0.10.0.tar.gz", hash = "sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9"}, 233 | ] 234 | more-itertools = [ 235 | {file = "more-itertools-8.4.0.tar.gz", hash = "sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5"}, 236 | {file = "more_itertools-8.4.0-py3-none-any.whl", hash = "sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2"}, 237 | ] 238 | packaging = [ 239 | {file = "packaging-20.4-py2.py3-none-any.whl", hash = "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181"}, 240 | {file = "packaging-20.4.tar.gz", hash = "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8"}, 241 | ] 242 | pluggy = [ 243 | {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, 244 | {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, 245 | ] 246 | py = [ 247 | {file = "py-1.9.0-py2.py3-none-any.whl", hash = "sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2"}, 248 | {file = "py-1.9.0.tar.gz", hash = "sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342"}, 249 | ] 250 | pyparsing = [ 251 | {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, 252 | {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, 253 | ] 254 | pytest = [ 255 | {file = "pytest-5.4.3-py3-none-any.whl", hash = "sha256:5c0db86b698e8f170ba4582a492248919255fcd4c79b1ee64ace34301fb589a1"}, 256 | {file = "pytest-5.4.3.tar.gz", hash = "sha256:7979331bfcba207414f5e1263b5a0f8f521d0f457318836a7355531ed1a4c7d8"}, 257 | ] 258 | python-dateutil = [ 259 | {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, 260 | {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, 261 | ] 262 | s3transfer = [ 263 | {file = "s3transfer-0.3.3-py2.py3-none-any.whl", hash = "sha256:2482b4259524933a022d59da830f51bd746db62f047d6eb213f2f8855dcb8a13"}, 264 | {file = "s3transfer-0.3.3.tar.gz", hash = "sha256:921a37e2aefc64145e7b73d50c71bb4f26f46e4c9f414dc648c6245ff92cf7db"}, 265 | ] 266 | six = [ 267 | {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, 268 | {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, 269 | ] 270 | urllib3 = [ 271 | {file = "urllib3-1.25.9-py2.py3-none-any.whl", hash = "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115"}, 272 | {file = "urllib3-1.25.9.tar.gz", hash = "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527"}, 273 | ] 274 | wcwidth = [ 275 | {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, 276 | {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, 277 | ] 278 | -------------------------------------------------------------------------------- /src/aws_iot_jobs_interface.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | /** 17 | * @file aws_iot_jobs_interface.h 18 | * @brief An interface for interacting with the AWS IoT Jobs system. 19 | * 20 | * This file defines utility functions for interacting with the AWS IoT jobs 21 | * APIs over MQTT. It provides functions for managing subscriptions to job 22 | * related topics and for sending queries and updates requests for jobs. 23 | * Callers are responsible for managing the subscriptions and associating 24 | * responses with the queries and update messages. 25 | */ 26 | #ifndef AWS_IOT_JOBS_INTERFACE_H_ 27 | #define AWS_IOT_JOBS_INTERFACE_H_ 28 | 29 | #ifdef DISABLE_IOT_JOBS 30 | #error "Jobs API is disabled" 31 | #endif 32 | 33 | /** 34 | * @file aws_iot_jobs_interface.h 35 | * @brief Functions for interacting with the AWS IoT Jobs system. 36 | */ 37 | #include "aws_iot_mqtt_client_interface.h" 38 | #include "aws_iot_jobs_topics.h" 39 | #include "aws_iot_jobs_types.h" 40 | #include "aws_iot_error.h" 41 | #include "aws_iot_json_utils.h" 42 | 43 | #ifdef __cplusplus 44 | extern "C" { 45 | #endif 46 | 47 | /** 48 | * @brief Subscribe to jobs messages for the given thing and/or jobs. 49 | * 50 | * The function can be used to subscribe to all job related messages. To subscribe 51 | * to messages not related to a job the jobId passed should be null. The jobId 52 | * can also be "+" to subscribe to messages related to any job, or "$next" to 53 | * indicate the next pending job. 54 | * 55 | * See also #aws_iot_jobs_subscribe_to_all_job_messages to subscribe to all possible 56 | * messages in one operation. 57 | * 58 | * \note Subscribing with the same thing, job and topic type more than 59 | * once is undefined. 60 | * 61 | * \param pClient the client to use 62 | * \param qos the qos to use 63 | * \param thingName the name of the thing to subscribe to 64 | * \param jobId the job id to subscribe to. To subscribe to messages not related to 65 | * a job the jobId passed should be null. The jobId can also be "+" to subscribe to 66 | * messages related to any job, or "$next" to indicate the next pending job. 67 | * \param topicType the topic type to subscribe to 68 | * \param replyType the reply topic type to subscribe to 69 | * \param pApplicationHandler the callback handler 70 | * \param pApplicationHandlerData the callback context data. This must remain valid at least until 71 | * aws_iot_jobs_unsubscribe_from_job_messages is called. 72 | * \param topicBuffer. A buffer to use to hold the topic name for the subscription. This buffer 73 | * must remain valid at least until aws_iot_jobs_unsubscribe_from_job_messages is called. 74 | * \param topicBufferSize the size of the topic buffer. The function will fail 75 | * with LIMIT_EXCEEDED_ERROR if this is too small. 76 | * \return the result of subscribing to the topic (see aws_iot_mqtt_subscribe) 77 | */ 78 | IoT_Error_t aws_iot_jobs_subscribe_to_job_messages( 79 | AWS_IoT_Client *pClient, QoS qos, 80 | const char *thingName, 81 | const char *jobId, 82 | AwsIotJobExecutionTopicType topicType, 83 | AwsIotJobExecutionTopicReplyType replyType, 84 | pApplicationHandler_t pApplicationHandler, 85 | void *pApplicationHandlerData, 86 | char *topicBuffer, 87 | uint16_t topicBufferSize); 88 | 89 | /** 90 | * @brief Subscribe to all job messages. 91 | * 92 | * Subscribe to all job messages for the given thing. 93 | * 94 | * \note Subscribing with the same thing more than once is undefined. 95 | * 96 | * \param pClient the client to use 97 | * \param qos the qos to use 98 | * \param thingName the name of the thing to subscribe to 99 | * \param pApplicationHandler the callback handler 100 | * \param pApplicationHandlerData the callback context data. This must remain valid at least until 101 | * aws_iot_jobs_unsubscribe_from_job_messages is called. 102 | * \param topicBuffer. A buffer to use to hold the topic name for the subscription. This buffer 103 | * must remain valid at least until aws_iot_jobs_unsubscribe_from_job_messages is called. 104 | * \param topicBufferSize the size of the topic buffer. The function will fail 105 | * with LIMIT_EXCEEDED_ERROR if this is too small. 106 | * \return the result of subscribing to the topic (see aws_iot_mqtt_subscribe) 107 | */ 108 | IoT_Error_t aws_iot_jobs_subscribe_to_all_job_messages( 109 | AWS_IoT_Client *pClient, QoS qos, 110 | const char *thingName, 111 | pApplicationHandler_t pApplicationHandler, 112 | void *pApplicationHandlerData, 113 | char *topicBuffer, 114 | uint16_t topicBufferSize); 115 | 116 | /** 117 | * @brief Unsubscribe from a job subscription 118 | * 119 | * Remove the subscription created using #aws_iot_jobs_subscribe_to_job_messages or 120 | * #aws_iot_jobs_subscribe_to_all_job_messages. 121 | * 122 | * \param pClient the client to use 123 | * \param topicBuffer the topic buffer passed to #aws_iot_jobs_subscribe_to_job_messages or 124 | * #aws_iot_jobs_subscribe_to_all_job_messages when the subscription was created. 125 | * \return #SUCCESS or the first error encountered. 126 | */ 127 | IoT_Error_t aws_iot_jobs_unsubscribe_from_job_messages( 128 | AWS_IoT_Client *pClient, 129 | char *topicBuffer); 130 | 131 | /** 132 | * @brief Send a query to one of the job query APIs. 133 | * 134 | * Send a query to one of the job query APIs. If jobId is null this 135 | * requests a list of pending jobs for the thing. If jobId is 136 | * not null then it sends a query for the details of that job. 137 | * If jobId is $next then it sends a query for the details for 138 | * the next pending job. 139 | * 140 | * \param pClient the client to use 141 | * \param qos the qos to use 142 | * \param thingName the thing name to query for 143 | * \param jobId the id of the job to query for. If null a list 144 | * of all pending jobs for the thing is requested. 145 | * \param clientToken the client token to use for the query. 146 | * If null no clientToken is sent resulting in an empty message. 147 | * \param topicBuffer the topic buffer to use. This may be discarded 148 | * as soon as this function returns 149 | * \param topicBufferSize the size of topicBuffer 150 | * \param messageBuffer the message buffer to use. May be NULL 151 | * if clientToken is NULL 152 | * \param messageBufferSize the size of messageBuffer 153 | * \param topicType the topic type to publish query to 154 | * \return LIMIT_EXCEEDED_ERROR if the topic buffer or 155 | * message buffer is too small, NULL_VALUE_ERROR if the any of 156 | * the required inputs are NULL, otherwise the result 157 | * of the mqtt publish 158 | */ 159 | IoT_Error_t aws_iot_jobs_send_query( 160 | AWS_IoT_Client *pClient, QoS qos, 161 | const char *thingName, 162 | const char *jobId, 163 | const char *clientToken, 164 | char *topicBuffer, 165 | uint16_t topicBufferSize, 166 | char *messageBuffer, 167 | size_t messageBufferSize, 168 | AwsIotJobExecutionTopicType topicType); 169 | 170 | /** 171 | * @brief Send a start next command to the job start-next API. 172 | * 173 | * Send a start next command to the job start-next API. 174 | * 175 | * \param pClient the client to use 176 | * \param qos the qos to use 177 | * \param thingName the thing name to query for 178 | * \param startNextRequest the start-next request to send 179 | * \param topicBuffer the topic buffer to use. This may be discarded 180 | * as soon as this function returns 181 | * \param topicBufferSize the size of topicBuffer 182 | * \param messageBuffer the message buffer to use. May be NULL 183 | * if clientToken is NULL 184 | * \param messageBufferSize the size of messageBuffer 185 | * \return LIMIT_EXCEEDED_ERROR if the topic buffer or 186 | * message buffer is too small, NULL_VALUE_ERROR if the any of 187 | * the required inputs are NULL, otherwise the result 188 | * of the mqtt publish 189 | */ 190 | IoT_Error_t aws_iot_jobs_start_next( 191 | AWS_IoT_Client *pClient, QoS qos, 192 | const char *thingName, 193 | const AwsIotStartNextPendingJobExecutionRequest *startNextRequest, 194 | char *topicBuffer, 195 | uint16_t topicBufferSize, 196 | char *messageBuffer, 197 | size_t messageBufferSize); 198 | 199 | /** 200 | * @brief Send a describe job query to the job query API. 201 | * 202 | * Send a describe job query to the job query API. If jobId is null this 203 | * requests a list of pending jobs for the thing. If jobId is 204 | * not null then it sends a query for the details of that job. 205 | * 206 | * \param pClient the client to use 207 | * \param qos the qos to use 208 | * \param thingName the thing name to query for 209 | * \param jobId the id of the job to query for. If null a list 210 | * of all pending jobs for the thing is requested. 211 | * \param describeRequest the describe request to send 212 | * \param topicBuffer the topic buffer to use. This may be discarded 213 | * as soon as this function returns 214 | * \param topicBufferSize the size of topicBuffer 215 | * \param messageBuffer the message buffer to use. May be NULL 216 | * if clientToken is NULL 217 | * \param messageBufferSize the size of messageBuffer 218 | * \return LIMIT_EXCEEDED_ERROR if the topic buffer or 219 | * message buffer is too small, NULL_VALUE_ERROR if the any of 220 | * the required inputs are NULL, otherwise the result 221 | * of the mqtt publish 222 | */ 223 | IoT_Error_t aws_iot_jobs_describe( 224 | AWS_IoT_Client *pClient, QoS qos, 225 | const char *thingName, 226 | const char *jobId, 227 | const AwsIotDescribeJobExecutionRequest *describeRequest, 228 | char *topicBuffer, 229 | uint16_t topicBufferSize, 230 | char *messageBuffer, 231 | size_t messageBufferSize); 232 | 233 | /** 234 | * @brief Send an update about a job execution. 235 | * 236 | * Send an update about a job execution. 237 | * 238 | * \param pClient the client to use 239 | * \param qos the qos to use 240 | * \param thingName the thing name to send the update for 241 | * \param jobId the id of the job to send the update for 242 | * \param updateRequest the update request to send 243 | * \param topicBuffer the topic buffer to use. This may be discarded 244 | * as soon as this function returns 245 | * \param topicBufferSize the size of topicBuffer 246 | * \param messageBuffer the message buffer to use. 247 | * \param messageBufferSize the size of messageBuffer 248 | * \return LIMIT_EXCEEDED_ERROR if the topic buffer or 249 | * message buffer is too small, NULL_VALUE_ERROR if the any of 250 | * the required inputs are NULL, otherwise the result 251 | * of the mqtt publish 252 | */ 253 | IoT_Error_t aws_iot_jobs_send_update( 254 | AWS_IoT_Client *pClient, QoS qos, 255 | const char *thingName, 256 | const char *jobId, 257 | const AwsIotJobExecutionUpdateRequest *updateRequest, 258 | char *topicBuffer, 259 | uint16_t topicBufferSize, 260 | char *messageBuffer, 261 | size_t messageBufferSize); 262 | 263 | #ifdef __cplusplus 264 | } 265 | #endif 266 | 267 | #endif /* AWS_IOT_JOBS_INTERFACE_H_ */ 268 | -------------------------------------------------------------------------------- /src/jsonParser.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "jsonParser.h" 6 | 7 | /** 8 | * Creates a new parser based over a given buffer with an array of tokens 9 | * available. 10 | */ 11 | void jsmnClass::Init(jsmn_parser_t *tokenParser) 12 | { 13 | tokenParser->pos = 0; 14 | tokenParser->toknext = 0; 15 | tokenParser->toksuper = -1; 16 | } 17 | 18 | 19 | int jsmnClass::equate(const char *json, jsmntok_t *tok, const char *s) 20 | { 21 | if (tok->type == JSMN_STRING && (int) strlen(s) == tok->end - tok->start && 22 | strncmp(json + tok->start, s, tok->end - tok->start) == 0) 23 | { 24 | return 0; 25 | } 26 | return -1; 27 | } 28 | 29 | 30 | jsmntok_t *jsmnClass::allocToken(jsmn_parser_t *tokenParser, jsmntok_t *tokens, size_t num_tokens) 31 | { 32 | jsmntok_t *tok; 33 | if (tokenParser->toknext >= num_tokens) { 34 | return NULL; 35 | } 36 | tok = &tokens[tokenParser->toknext++]; 37 | tok->start = tok->end = -1; 38 | tok->size = 0; 39 | #ifdef JSMN_PARENT_LINKS 40 | tok->parent = -1; 41 | #endif 42 | return tok; 43 | } 44 | 45 | /** 46 | * Fills token type and boundaries. 47 | */ 48 | void jsmnClass::fillToken(jsmntok_t *token, jsmntype_t type, int start, int end) 49 | { 50 | token->type = type; 51 | token->start = start; 52 | token->end = end; 53 | token->size = 0; 54 | } 55 | 56 | /** 57 | * Fills next available token with JSON primitive. 58 | */ 59 | int jsmnClass::parsePrimitive(jsmn_parser_t *tokenParser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens) 60 | { 61 | jsmntok_t *token; 62 | int start; 63 | 64 | start = tokenParser->pos; 65 | 66 | for (; tokenParser->pos < len && js[tokenParser->pos] != '\0'; tokenParser->pos++) { 67 | switch (js[tokenParser->pos]) { 68 | #ifndef JSMN_STRICT 69 | /* In strict mode primitive must be followed by "," or "}" or "]" */ 70 | case ':': 71 | #endif 72 | case '\t' : case '\r' : case '\n' : case ' ' : 73 | case ',' : case ']' : case '}' : 74 | goto found; 75 | } 76 | if (js[tokenParser->pos] < 32 || js[tokenParser->pos] >= 127) { 77 | tokenParser->pos = start; 78 | return JSMN_ERROR_INVAL; 79 | } 80 | } 81 | #ifdef JSMN_STRICT 82 | /* In strict mode primitive must be followed by a comma/object/array */ 83 | tokenParser->pos = start; 84 | return JSMN_ERROR_PART; 85 | #endif 86 | 87 | found: 88 | if (tokens == NULL) { 89 | tokenParser->pos--; 90 | return 0; 91 | } 92 | token = allocToken(tokenParser, tokens, num_tokens); 93 | if (token == NULL) { 94 | tokenParser->pos = start; 95 | return JSMN_ERROR_NOMEM; 96 | } 97 | fillToken(token, JSMN_PRIMITIVE, start, tokenParser->pos); 98 | #ifdef JSMN_PARENT_LINKS 99 | token->parent = tokenParser->toksuper; 100 | #endif 101 | tokenParser->pos--; 102 | return 0; 103 | } 104 | 105 | /** 106 | * Fills next token with JSON string. 107 | */ 108 | int jsmnClass::parseString(jsmn_parser_t *tokenParser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens) 109 | { 110 | jsmntok_t *token; 111 | 112 | int start = tokenParser->pos; 113 | 114 | tokenParser->pos++; 115 | 116 | /* Skip starting quote */ 117 | for (; tokenParser->pos < len && js[tokenParser->pos] != '\0'; tokenParser->pos++) { 118 | char c = js[tokenParser->pos]; 119 | 120 | /* Quote: end of string */ 121 | if (c == '\"') { 122 | if (tokens == NULL) { 123 | return 0; 124 | } 125 | token = allocToken(tokenParser, tokens, num_tokens); 126 | if (token == NULL) { 127 | tokenParser->pos = start; 128 | return JSMN_ERROR_NOMEM; 129 | } 130 | fillToken(token, JSMN_STRING, start+1, tokenParser->pos); 131 | #ifdef JSMN_PARENT_LINKS 132 | token->parent = tokenParser->toksuper; 133 | #endif 134 | return 0; 135 | } 136 | 137 | /* Backslash: Quoted symbol expected */ 138 | if (c == '\\' && tokenParser->pos + 1 < len) { 139 | int i; 140 | tokenParser->pos++; 141 | switch (js[tokenParser->pos]) { 142 | /* Allowed escaped symbols */ 143 | case '\"': case '/' : case '\\' : case 'b' : 144 | case 'f' : case 'r' : case 'n' : case 't' : 145 | break; 146 | /* Allows escaped symbol \uXXXX */ 147 | case 'u': 148 | tokenParser->pos++; 149 | for(i = 0; i < 4 && tokenParser->pos < len && js[tokenParser->pos] != '\0'; i++) { 150 | /* If it isn't a hex character we have an error */ 151 | if(!((js[tokenParser->pos] >= 48 && js[tokenParser->pos] <= 57) || /* 0-9 */ 152 | (js[tokenParser->pos] >= 65 && js[tokenParser->pos] <= 70) || /* A-F */ 153 | (js[tokenParser->pos] >= 97 && js[tokenParser->pos] <= 102))) { /* a-f */ 154 | tokenParser->pos = start; 155 | return JSMN_ERROR_INVAL; 156 | } 157 | tokenParser->pos++; 158 | } 159 | tokenParser->pos--; 160 | break; 161 | /* Unexpected symbol */ 162 | default: 163 | tokenParser->pos = start; 164 | return JSMN_ERROR_INVAL; 165 | } 166 | } 167 | } 168 | tokenParser->pos = start; 169 | return JSMN_ERROR_PART; 170 | } 171 | 172 | 173 | /** 174 | * Parse JSON string and fill tokens. 175 | */ 176 | int jsmnClass::parse(jsmn_parser_t *tokenParser, const char *js, size_t len, jsmntok_t *tokens, unsigned int num_tokens) 177 | { 178 | int r; 179 | int i; 180 | jsmntok_t *token; 181 | int count = tokenParser->toknext; 182 | 183 | for (; tokenParser->pos < len && js[tokenParser->pos] != '\0'; tokenParser->pos++) { 184 | char c; 185 | jsmntype_t type; 186 | 187 | c = js[tokenParser->pos]; 188 | 189 | switch (c) { 190 | case '{': case '[': 191 | count++; 192 | if (tokens == NULL) { 193 | break; 194 | } 195 | token = allocToken(tokenParser, tokens, num_tokens); 196 | if (token == NULL) 197 | return JSMN_ERROR_NOMEM; 198 | if (tokenParser->toksuper != -1) { 199 | tokens[tokenParser->toksuper].size++; 200 | #ifdef JSMN_PARENT_LINKS 201 | token->parent = tokenParser->toksuper; 202 | #endif 203 | } 204 | token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); 205 | token->start = tokenParser->pos; 206 | tokenParser->toksuper = tokenParser->toknext - 1; 207 | break; 208 | case '}': case ']': 209 | if (tokens == NULL) 210 | break; 211 | type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); 212 | #ifdef JSMN_PARENT_LINKS 213 | if (tokenParser->toknext < 1) { 214 | return JSMN_ERROR_INVAL; 215 | } 216 | token = &tokens[tokenParser->toknext - 1]; 217 | for (;;) { 218 | if (token->start != -1 && token->end == -1) { 219 | if (token->type != type) { 220 | return JSMN_ERROR_INVAL; 221 | } 222 | token->end = tokenParser->pos + 1; 223 | tokenParser->toksuper = token->parent; 224 | break; 225 | } 226 | if (token->parent == -1) { 227 | if(token->type != type || tokenParser->toksuper == -1) { 228 | return JSMN_ERROR_INVAL; 229 | } 230 | break; 231 | } 232 | token = &tokens[token->parent]; 233 | } 234 | #else 235 | for (i = tokenParser->toknext - 1; i >= 0; i--) { 236 | token = &tokens[i]; 237 | if (token->start != -1 && token->end == -1) { 238 | if (token->type != type) { 239 | return JSMN_ERROR_INVAL; 240 | } 241 | tokenParser->toksuper = -1; 242 | token->end = tokenParser->pos + 1; 243 | break; 244 | } 245 | } 246 | /* Error if unmatched closing bracket */ 247 | if (i == -1) return JSMN_ERROR_INVAL; 248 | for (; i >= 0; i--) { 249 | token = &tokens[i]; 250 | if (token->start != -1 && token->end == -1) { 251 | tokenParser->toksuper = i; 252 | break; 253 | } 254 | } 255 | #endif 256 | break; 257 | case '\"': 258 | r = parseString(tokenParser, js, len, tokens, num_tokens); 259 | if (r < 0) return r; 260 | count++; 261 | if (tokenParser->toksuper != -1 && tokens != NULL) 262 | tokens[tokenParser->toksuper].size++; 263 | break; 264 | case '\t' : case '\r' : case '\n' : case ' ': 265 | break; 266 | case ':': 267 | tokenParser->toksuper = tokenParser->toknext - 1; 268 | break; 269 | case ',': 270 | if (tokens != NULL && tokenParser->toksuper != -1 && 271 | tokens[tokenParser->toksuper].type != JSMN_ARRAY && 272 | tokens[tokenParser->toksuper].type != JSMN_OBJECT) { 273 | #ifdef JSMN_PARENT_LINKS 274 | tokenParser->toksuper = tokens[tokenParser->toksuper].parent; 275 | #else 276 | for (i = tokenParser->toknext - 1; i >= 0; i--) { 277 | if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) { 278 | if (tokens[i].start != -1 && tokens[i].end == -1) { 279 | tokenParser->toksuper = i; 280 | break; 281 | } 282 | } 283 | } 284 | #endif 285 | } 286 | break; 287 | #ifdef JSMN_STRICT 288 | /* In strict mode primitives are: numbers and booleans */ 289 | case '-': case '0': case '1' : case '2': case '3' : case '4': 290 | case '5': case '6': case '7' : case '8': case '9': 291 | case 't': case 'f': case 'n' : 292 | /* And they must not be keys of the object */ 293 | if (tokens != NULL && tokenParser->toksuper != -1) { 294 | jsmntok_t *t = &tokens[tokenParser->toksuper]; 295 | if (t->type == JSMN_OBJECT || 296 | (t->type == JSMN_STRING && t->size != 0)) { 297 | return JSMN_ERROR_INVAL; 298 | } 299 | } 300 | #else 301 | /* In non-strict mode every unquoted value is a primitive */ 302 | default: 303 | #endif 304 | r = parsePrimitive(tokenParser, js, len, tokens, num_tokens); 305 | if (r < 0) return r; 306 | count++; 307 | if (tokenParser->toksuper != -1 && tokens != NULL) 308 | tokens[tokenParser->toksuper].size++; 309 | break; 310 | 311 | #ifdef JSMN_STRICT 312 | /* Unexpected char in strict mode */ 313 | default: 314 | return JSMN_ERROR_INVAL; 315 | #endif 316 | } 317 | } 318 | 319 | if (tokens != NULL) { 320 | for (i = tokenParser->toknext - 1; i >= 0; i--) { 321 | /* Unmatched opened object or array */ 322 | if (tokens[i].start != -1 && tokens[i].end == -1) { 323 | return JSMN_ERROR_PART; 324 | } 325 | } 326 | } 327 | 328 | return count; 329 | } 330 | 331 | jsmnClass jsmn; 332 | -------------------------------------------------------------------------------- /src/aws_iot_mqtt_client_yield.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | // Based on Eclipse Paho. 17 | /******************************************************************************* 18 | * Copyright (c) 2014 IBM Corp. 19 | * 20 | * All rights reserved. This program and the accompanying materials 21 | * are made available under the terms of the Eclipse Public License v1.0 22 | * and Eclipse Distribution License v1.0 which accompany this distribution. 23 | * 24 | * The Eclipse Public License is available at 25 | * http://www.eclipse.org/legal/epl-v10.html 26 | * and the Eclipse Distribution License is available at 27 | * http://www.eclipse.org/org/documents/edl-v10.php. 28 | * 29 | * Contributors: 30 | * Allan Stockdill-Mander/Ian Craggs - initial API and implementation and/or initial documentation 31 | *******************************************************************************/ 32 | 33 | /** 34 | * @file aws_iot_mqtt_client_yield.c 35 | * @brief MQTT client yield API definitions 36 | */ 37 | 38 | #ifdef __cplusplus 39 | extern "C" { 40 | #endif 41 | 42 | #include "aws_iot_mqtt_client_common_internal.h" 43 | 44 | /** 45 | * This is for the case when the aws_iot_mqtt_internal_send_packet Fails. 46 | */ 47 | static void _aws_iot_mqtt_force_client_disconnect(AWS_IoT_Client *pClient) { 48 | pClient->clientStatus.clientState = CLIENT_STATE_DISCONNECTED_ERROR; 49 | pClient->networkStack.disconnect(&(pClient->networkStack)); 50 | pClient->networkStack.destroy(&(pClient->networkStack)); 51 | } 52 | 53 | static IoT_Error_t _aws_iot_mqtt_handle_disconnect(AWS_IoT_Client *pClient) { 54 | IoT_Error_t rc; 55 | 56 | FUNC_ENTRY; 57 | 58 | rc = aws_iot_mqtt_disconnect(pClient); 59 | if(rc != SUCCESS) { 60 | // If the aws_iot_mqtt_internal_send_packet prevents us from sending a disconnect packet then we have to clean the stack 61 | _aws_iot_mqtt_force_client_disconnect(pClient); 62 | } 63 | 64 | if(NULL != pClient->clientData.disconnectHandler) { 65 | pClient->clientData.disconnectHandler(pClient, pClient->clientData.disconnectHandlerData); 66 | } 67 | 68 | /* Reset to 0 since this was not a manual disconnect */ 69 | pClient->clientStatus.clientState = CLIENT_STATE_DISCONNECTED_ERROR; 70 | FUNC_EXIT_RC(NETWORK_DISCONNECTED_ERROR); 71 | } 72 | 73 | 74 | static IoT_Error_t _aws_iot_mqtt_handle_reconnect(AWS_IoT_Client *pClient) { 75 | IoT_Error_t rc; 76 | 77 | FUNC_ENTRY; 78 | 79 | if(!has_timer_expired(&(pClient->reconnectDelayTimer))) { 80 | /* Timer has not expired. Not time to attempt reconnect yet. 81 | * Return attempting reconnect */ 82 | FUNC_EXIT_RC(NETWORK_ATTEMPTING_RECONNECT); 83 | } 84 | 85 | rc = NETWORK_PHYSICAL_LAYER_DISCONNECTED; 86 | if(NULL != pClient->networkStack.isConnected) { 87 | rc = pClient->networkStack.isConnected(&(pClient->networkStack)); 88 | } 89 | 90 | if(NETWORK_PHYSICAL_LAYER_CONNECTED == rc) { 91 | rc = aws_iot_mqtt_attempt_reconnect(pClient); 92 | if(NETWORK_RECONNECTED == rc) { 93 | rc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTED_IDLE, 94 | CLIENT_STATE_CONNECTED_YIELD_IN_PROGRESS); 95 | if(SUCCESS != rc) { 96 | FUNC_EXIT_RC(rc); 97 | } 98 | FUNC_EXIT_RC(NETWORK_RECONNECTED); 99 | } 100 | } 101 | 102 | pClient->clientData.currentReconnectWaitInterval *= 2; 103 | 104 | if(AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL < pClient->clientData.currentReconnectWaitInterval) { 105 | FUNC_EXIT_RC(NETWORK_RECONNECT_TIMED_OUT_ERROR); 106 | } 107 | countdown_ms(&(pClient->reconnectDelayTimer), pClient->clientData.currentReconnectWaitInterval); 108 | FUNC_EXIT_RC(rc); 109 | } 110 | 111 | static IoT_Error_t _aws_iot_mqtt_keep_alive(AWS_IoT_Client *pClient) { 112 | IoT_Error_t rc = SUCCESS; 113 | Timer timer; 114 | size_t serialized_len; 115 | 116 | FUNC_ENTRY; 117 | 118 | if(NULL == pClient) { 119 | FUNC_EXIT_RC(NULL_VALUE_ERROR); 120 | } 121 | 122 | if(0 == pClient->clientData.keepAliveInterval) { 123 | FUNC_EXIT_RC(SUCCESS); 124 | } 125 | 126 | if(!has_timer_expired(&pClient->pingTimer)) { 127 | FUNC_EXIT_RC(SUCCESS); 128 | } 129 | 130 | if(pClient->clientStatus.isPingOutstanding) { 131 | rc = _aws_iot_mqtt_handle_disconnect(pClient); 132 | FUNC_EXIT_RC(rc); 133 | } 134 | 135 | /* there is no ping outstanding - send one */ 136 | init_timer(&timer); 137 | 138 | countdown_ms(&timer, pClient->clientData.commandTimeoutMs); 139 | serialized_len = 0; 140 | rc = aws_iot_mqtt_internal_serialize_zero(pClient->clientData.writeBuf, pClient->clientData.writeBufSize, 141 | PINGREQ, &serialized_len); 142 | if(SUCCESS != rc) { 143 | FUNC_EXIT_RC(rc); 144 | } 145 | 146 | /* send the ping packet */ 147 | rc = aws_iot_mqtt_internal_send_packet(pClient, serialized_len, &timer); 148 | if(SUCCESS != rc) { 149 | //If sending a PING fails we can no longer determine if we are connected. In this case we decide we are disconnected and begin reconnection attempts 150 | rc = _aws_iot_mqtt_handle_disconnect(pClient); 151 | FUNC_EXIT_RC(rc); 152 | } 153 | 154 | pClient->clientStatus.isPingOutstanding = true; 155 | /* start a timer to wait for PINGRESP from server */ 156 | countdown_sec(&pClient->pingTimer, pClient->clientData.keepAliveInterval); 157 | 158 | FUNC_EXIT_RC(SUCCESS); 159 | } 160 | 161 | /** 162 | * @brief Yield to the MQTT client 163 | * 164 | * Called to yield the current thread to the underlying MQTT client. This time is used by 165 | * the MQTT client to manage PING requests to monitor the health of the TCP connection as 166 | * well as periodically check the socket receive buffer for subscribe messages. Yield() 167 | * must be called at a rate faster than the keepalive interval. It must also be called 168 | * at a rate faster than the incoming message rate as this is the only way the client receives 169 | * processing time to manage incoming messages. 170 | * This is the internal function which is called by the yield API to perform the operation. 171 | * Not meant to be called directly as it doesn't do validations or client state changes 172 | * 173 | * @param pClient Reference to the IoT Client 174 | * @param timeout_ms Maximum number of milliseconds to pass thread execution to the client. 175 | * 176 | * @return An IoT Error Type defining successful/failed client processing. 177 | * If this call results in an error it is likely the MQTT connection has dropped. 178 | * iot_is_mqtt_connected can be called to confirm. 179 | */ 180 | 181 | static IoT_Error_t _aws_iot_mqtt_internal_yield(AWS_IoT_Client *pClient, uint32_t timeout_ms) { 182 | IoT_Error_t yieldRc = SUCCESS; 183 | 184 | uint8_t packet_type; 185 | ClientState clientState; 186 | Timer timer; 187 | init_timer(&timer); 188 | countdown_ms(&timer, timeout_ms); 189 | 190 | FUNC_ENTRY; 191 | 192 | // evaluate timeout at the end of the loop to make sure the actual yield runs at least once 193 | do { 194 | clientState = aws_iot_mqtt_get_client_state(pClient); 195 | if(CLIENT_STATE_PENDING_RECONNECT == clientState) { 196 | if(AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL < pClient->clientData.currentReconnectWaitInterval) { 197 | yieldRc = NETWORK_RECONNECT_TIMED_OUT_ERROR; 198 | break; 199 | } 200 | yieldRc = _aws_iot_mqtt_handle_reconnect(pClient); 201 | /* Network reconnect attempted, check if yield timer expired before 202 | * doing anything else */ 203 | continue; 204 | } 205 | 206 | yieldRc = aws_iot_mqtt_internal_cycle_read(pClient, &timer, &packet_type); 207 | if(SUCCESS == yieldRc) { 208 | yieldRc = _aws_iot_mqtt_keep_alive(pClient); 209 | } else { 210 | // SSL read and write errors are terminal, connection must be closed and retried 211 | if(NETWORK_SSL_READ_ERROR == yieldRc || NETWORK_SSL_WRITE_ERROR == yieldRc || NETWORK_SSL_WRITE_TIMEOUT_ERROR == yieldRc) { 212 | yieldRc = _aws_iot_mqtt_handle_disconnect(pClient); 213 | } 214 | } 215 | 216 | if(NETWORK_DISCONNECTED_ERROR == yieldRc) { 217 | pClient->clientData.counterNetworkDisconnected++; 218 | if(1 == pClient->clientStatus.isAutoReconnectEnabled) { 219 | yieldRc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_DISCONNECTED_ERROR, 220 | CLIENT_STATE_PENDING_RECONNECT); 221 | if(SUCCESS != yieldRc) { 222 | FUNC_EXIT_RC(yieldRc); 223 | } 224 | 225 | pClient->clientData.currentReconnectWaitInterval = AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL; 226 | countdown_ms(&(pClient->reconnectDelayTimer), pClient->clientData.currentReconnectWaitInterval); 227 | /* Depending on timer values, it is possible that yield timer has expired 228 | * Set to rc to attempting reconnect to inform client that autoreconnect 229 | * attempt has started */ 230 | yieldRc = NETWORK_ATTEMPTING_RECONNECT; 231 | } else { 232 | break; 233 | } 234 | } else if(SUCCESS != yieldRc) { 235 | break; 236 | } 237 | } while(!has_timer_expired(&timer)); 238 | 239 | FUNC_EXIT_RC(yieldRc); 240 | } 241 | 242 | /** 243 | * @brief Yield to the MQTT client 244 | * 245 | * Called to yield the current thread to the underlying MQTT client. This time is used by 246 | * the MQTT client to manage PING requests to monitor the health of the TCP connection as 247 | * well as periodically check the socket receive buffer for subscribe messages. Yield() 248 | * must be called at a rate faster than the keepalive interval. It must also be called 249 | * at a rate faster than the incoming message rate as this is the only way the client receives 250 | * processing time to manage incoming messages. 251 | * This is the outer function which does the validations and calls the internal yield above 252 | * to perform the actual operation. It is also responsible for client state changes 253 | * 254 | * @param pClient Reference to the IoT Client 255 | * @param timeout_ms Maximum number of milliseconds to pass thread execution to the client. 256 | * 257 | * @return An IoT Error Type defining successful/failed client processing. 258 | * If this call results in an error it is likely the MQTT connection has dropped. 259 | * iot_is_mqtt_connected can be called to confirm. 260 | */ 261 | IoT_Error_t aws_iot_mqtt_yield(AWS_IoT_Client *pClient, uint32_t timeout_ms) { 262 | IoT_Error_t rc, yieldRc; 263 | ClientState clientState; 264 | 265 | if(NULL == pClient || 0 == timeout_ms) { 266 | FUNC_EXIT_RC(NULL_VALUE_ERROR); 267 | } 268 | 269 | clientState = aws_iot_mqtt_get_client_state(pClient); 270 | /* Check if network was manually disconnected */ 271 | if(CLIENT_STATE_DISCONNECTED_MANUALLY == clientState) { 272 | FUNC_EXIT_RC(NETWORK_MANUALLY_DISCONNECTED); 273 | } 274 | 275 | /* If we are in the pending reconnect state, skip other checks. 276 | * Pending reconnect state is only set when auto-reconnect is enabled */ 277 | if(CLIENT_STATE_PENDING_RECONNECT != clientState) { 278 | /* Check if network is disconnected and auto-reconnect is not enabled */ 279 | if(!aws_iot_mqtt_is_client_connected(pClient)) { 280 | FUNC_EXIT_RC(NETWORK_DISCONNECTED_ERROR); 281 | } 282 | 283 | /* Check if client is idle, if not another operation is in progress and we should return */ 284 | if(CLIENT_STATE_CONNECTED_IDLE != clientState) { 285 | FUNC_EXIT_RC(MQTT_CLIENT_NOT_IDLE_ERROR); 286 | } 287 | 288 | rc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTED_IDLE, 289 | CLIENT_STATE_CONNECTED_YIELD_IN_PROGRESS); 290 | if(SUCCESS != rc) { 291 | FUNC_EXIT_RC(rc); 292 | } 293 | } 294 | 295 | yieldRc = _aws_iot_mqtt_internal_yield(pClient, timeout_ms); 296 | 297 | if(NETWORK_DISCONNECTED_ERROR != yieldRc && NETWORK_ATTEMPTING_RECONNECT != yieldRc) { 298 | rc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTED_YIELD_IN_PROGRESS, 299 | CLIENT_STATE_CONNECTED_IDLE); 300 | if(SUCCESS == yieldRc && SUCCESS != rc) { 301 | yieldRc = rc; 302 | } 303 | } 304 | 305 | FUNC_EXIT_RC(yieldRc); 306 | } 307 | 308 | #ifdef __cplusplus 309 | } 310 | #endif 311 | 312 | --------------------------------------------------------------------------------