Update ESP-IDF examples

This commit is contained in:
valeros
2020-09-01 21:48:00 +03:00
parent ff997d3677
commit 1ceb7b9d92
73 changed files with 1492 additions and 846 deletions
+4 -18
View File
@@ -7,10 +7,9 @@
; Please visit documentation for the other options and examples
; http://docs.platformio.org/page/projectconf.html
[env:esp32dev]
[env]
platform = espressif32
framework = arduino, espidf
board = esp32dev
build_flags =
-D CONFIG_BLINK_GPIO=2
monitor_speed = 115200
@@ -18,24 +17,11 @@ platform_packages =
; use a special branch
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#idf-release/v4.0
[env:esp32dev]
board = esp32dev
[env:espea32]
platform = espressif32
framework = arduino, espidf
board = espea32
build_flags =
-D CONFIG_BLINK_GPIO=2
monitor_speed = 115200
platform_packages =
; use a special branch
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#idf-release/v4.0
[env:esp320]
platform = espressif32
framework = arduino, espidf
board = esp320
build_flags =
-D CONFIG_BLINK_GPIO=2
monitor_speed = 115200
platform_packages =
; use a special branch
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#idf-release/v4.0
@@ -7,22 +7,16 @@
; Please visit documentation for the other options and examples
; http://docs.platformio.org/page/projectconf.html
[env:esp32dev]
[env]
platform = espressif32
framework = arduino, espidf
board = esp32dev
build_flags = -DCONFIG_WIFI_SSID=\"ESP_AP\" -DCONFIG_WIFI_PASSWORD=\"MYPASS\"
monitor_speed = 115200
platform_packages =
; use a special branch
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#idf-release/v4.0
[env:esp32dev]
board = esp32dev
[env:esp-wrover-kit]
platform = espressif32
framework = arduino
board = esp-wrover-kit
build_flags = -DCONFIG_WIFI_SSID=\"ESP_AP\" -DCONFIG_WIFI_PASSWORD=\"MYPASS\"
monitor_speed = 115200
platform_packages =
; use a special branch
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#idf-release/v4.0
@@ -15,4 +15,7 @@ CONFIG_ARDUHAL_PARTITION_SCHEME="default"
CONFIG_AUTOCONNECT_WIFI=y
CONFIG_ARDUINO_SELECTIVE_WiFi=y
CONFIG_MBEDTLS_PSK_MODES=y
CONFIG_MBEDTLS_KEY_EXCHANGE_PSK=y
CONFIG_MBEDTLS_KEY_EXCHANGE_PSK=y
# Example configs
CONFIG_EXAMPLE_WIFI_SSID="MYSSID"
CONFIG_EXAMPLE_WIFI_PASSWORD="MYPASS"
@@ -5,7 +5,7 @@ variables:
BATCH_BUILD: "1"
V: "0"
MAKEFLAGS: "-j5 --no-keep-going"
IDF_PATH: "$CI_PROJECT_DIR/idf/esp-idf"
IDF_PATH: "$CI_PROJECT_DIR/esp-idf"
build_demo:
stage: build
@@ -23,12 +23,11 @@ build_demo:
- echo -e "Host gitlab.espressif.cn\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
- git --version
- git submodule update --init --recursive
- mkdir idf
- cd idf
- git clone --depth 1 $GITLAB_SSH_SERVER/idf/esp-idf.git
- pushd esp-idf
- ./tools/ci/mirror-submodule-update.sh
- popd
- git clone --recursive --depth 1 $GITLAB_SSH_SERVER/idf/esp-idf.git
- export PATH="$IDF_PATH/tools:$PATH"
- cd esp-idf
- ./install.sh
- . export.sh
- cd ..
- cd examples/thing_shadow
- cat sdkconfig.ci >> sdkconfig.defaults
@@ -1,6 +0,0 @@
*Issue #, if available:*
*Description of changes:*
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
@@ -0,0 +1,22 @@
# Ignore executables
*.o
IotSdkC_tests
samples/linux/jobs_sample/jobs_sample
samples/linux/shadow_sample/shadow_sample
samples/linux/shadow_sample_console_echo/shadow_console_echo
samples/linux/subscribe_publish_library_sample/libAwsIotSdk.a
samples/linux/subscribe_publish_library_sample/subscribe_publish_library_sample
samples/linux/subscribe_publish_sample/subscribe_publish_sample
tests/integration/integration_tests_mbedtls
tests/integration/integration_tests_mbedtls_mt
# Ignore test artifacts
objs/*
testLibs/*
# Ignore CppUTest and mbed TLS
external_libs/CppUTest/*
external_libs/mbedTLS/*
# Ignore credentials
certs/*
@@ -1,27 +1,12 @@
language: c
# Get Coverity certificate.
before_install:
- echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-
# Coverity configuration.
addons:
coverity_scan:
project:
name: "aws-iot-device-sdk-embedded-C"
description: "SDK for connecting to AWS IoT from a device using embedded C. "
notification_email: nobody@amazon.com
build_command_prepend: "cd tests/integration"
build_command: "make app"
branch_pattern: master
install:
# Remove placeholders.
- rm external_libs/CppUTest/*
- rm -rf external_libs/mbedTLS
- rm external_libs/mbedTLS/*
# Get mbedtls.
- git clone https://github.com/ARMmbed/mbedtls.git external_libs/mbedTLS
- wget -qO- https://github.com/ARMmbed/mbedtls/archive/mbedtls-2.16.5.tar.gz | tar xvz -C external_libs/mbedTLS --strip-components=1
# Get CppUTest.
- wget -qO- https://github.com/cpputest/cpputest/archive/v3.6.tar.gz | tar xvz -C external_libs/CppUTest --strip-components=1
@@ -29,38 +14,31 @@ install:
script:
# Verify that the samples build.
- cd samples/linux/jobs_sample
- make
- make -j2
- cd ../shadow_sample
- make
- make -j2
- cd ../shadow_sample_console_echo
- make
- make -j2
- cd ../subscribe_publish_library_sample
- make
- make -j2
- cd ../subscribe_publish_sample
- make
- make -j2
# Set the AWS IoT endpoint.
- cd ../../../tests/integration
- sed -i 's/^.*#define AWS_IOT_MQTT_HOST.*$/#define AWS_IOT_MQTT_HOST "'"$INTEGRATION_TEST_ENDPOINT"'"/' include/aws_iot_config.h
# Build and run unit tests.
- cd ../../../
- make build-cpputest -j2
- make all_no_tests -j2
- ./IotSdkC_tests -v
# Build the integration tests.
- make app
# Set up integration tests if not a pull request.
- if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then cd tests/integration; fi
- if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then sed -i 's/^.*#define AWS_IOT_MQTT_HOST.*$/#define AWS_IOT_MQTT_HOST "'"$AWS_IOT_ENDPOINT"'"/' include/aws_iot_config.h; fi
- if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then make app -j2; fi
# Build the unit tests.
- cd ../../
- make build-cpputest
- make all_no_tests
# Import credentials for integration tests.
- if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then wget https://www.amazontrust.com/repository/AmazonRootCA1.pem -O ../../certs/rootCA.crt; fi
- if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then echo -e $AWS_IOT_CLIENT_CERT > ../../certs/cert.pem; fi
- if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then echo -e $AWS_IOT_PRIVATE_KEY > ../../certs/privkey.pem; fi
# Execute unit tests.
- ./IotSdkC_tests
# Import credentials.
- echo -e $INTEGRATION_TEST_CLIENT_CERT > certs/cert.pem
- echo -e $INTEGRATION_TEST_ROOT_CA > certs/rootCA.crt
- echo -e $INTEGRATION_TEST_PRIVATE_KEY > certs/privkey.pem
# Execute integration tests.
- cd tests/integration
- ./integration_tests_mbedtls
- ./integration_tests_mbedtls_mt
# Run integration tests.
- if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then ./integration_tests_mbedtls; fi
@@ -4,22 +4,22 @@
Bugfixes:
- [#167], [#168] Fixed issues reported by Coverity Scan.
- [#177] Fixes a memory corruption bug and handling of timeouts.
- [#167](https://github.com/aws/aws-iot-device-sdk-embedded-C/pull/167), [#168](https://github.com/aws/aws-iot-device-sdk-embedded-C/pull/168) Fixed issues reported by Coverity Scan.
- [#177](https://github.com/aws/aws-iot-device-sdk-embedded-C/pull/177) Fixes a memory corruption bug and handling of timeouts.
Other:
- Add .travis.yml for Travis CI.
- Removed C++ sample.
- Removed includes of `inttypes.h`, which doesn't exist on some systems.
- [#175] Added comments on static allocation of MQTT topics.
- [#175](https://github.com/aws/aws-iot-device-sdk-embedded-C/pull/175) Added comments on static allocation of MQTT topics.
## [3.0.0](https://github.com/aws/aws-iot-device-sdk-embedded-C/releases/tag/v3.0.0) (Apr 17, 2018)
Bugfixes:
- [#152] Fixes potential buffer overflows in `parseStringValue` by requiring a size parameter in `jsonStruct_t`.
- [#155] Fixes other memory corruption bugs; also improves stability.
- [#152](https://github.com/aws/aws-iot-device-sdk-embedded-C/pull/152) Fixes potential buffer overflows in `parseStringValue` by requiring a size parameter in `jsonStruct_t`.
- [#155](https://github.com/aws/aws-iot-device-sdk-embedded-C/pull/155) Fixes other memory corruption bugs; also improves stability.
The two bug fixes above are not backwards compatible with v2.3.0. Please see [README.md](README.md#migrating-from-2x-to-3x) for details on migrating to v3.0.0.
@@ -50,7 +50,7 @@ Pull requests:
## [2.2.0](https://github.com/aws/aws-iot-device-sdk-embedded-C/releases/tag/v2.2.0) (Nov 22, 2017)
New Features:
- Added SDK metrics string into connect packet
Bugfixes:
@@ -79,7 +79,7 @@ Improvements:
- Change default keepalive interval to 600 seconds
Pull requests:
- [#29](https://github.com/aws/aws-iot-device-sdk-embedded-C/pull/29) - three small fixes
- [#59](https://github.com/aws/aws-iot-device-sdk-embedded-C/pull/59) - Fixed MQTT header constructing and parsing
- [#88](https://github.com/aws/aws-iot-device-sdk-embedded-C/pull/88) - Fix username and password are confused
@@ -92,14 +92,14 @@ Pull requests:
Bugfixes/Improvements:
- Network layer interface improvements to address reported issues
- Incorporated GitHub pull request [#41](https://github.com/aws/aws-iot-device-sdk-embedded-c/pull/41)
- Incorporated GitHub pull request [#41](https://github.com/aws/aws-iot-device-sdk-embedded-c/pull/41)
- Bugfixes for issues [#36](https://github.com/aws/aws-iot-device-sdk-embedded-C/issues/36) and [#33](https://github.com/aws/aws-iot-device-sdk-embedded-C/issues/33)
## [2.1.0](https://github.com/aws/aws-iot-device-sdk-embedded-C/releases/tag/v2.1.0) (Jun 15, 2016)
New features:
- Added unit tests, further details can be found in the testing readme [here](https://github.com/aws/aws-iot-device-sdk-embedded-c/blob/master/tests/README.md)
- Added unit tests, further details can be found in the testing readme [here](https://github.com/aws/aws-iot-device-sdk-embedded-c/blob/master/tests/README.md/)
- Added sample to demonstrate building the SDK as library
- Added sample to demonstrate building the SDK in C++
@@ -109,7 +109,7 @@ Bugfixes/Improvements:
- Increased default value of MQTT Command Timeout in Shadow Connect to 20 secs
- Shadow null/length checks
- Client Id Length not passed correctly in shadow connect
- Add extern C to headers and source files, added sample to demonstrate usage with C++
- Add extern C to headers and source files, added sample to demonstrate usage with C++
- Delete/Accepted not being reported, callback added for delete/accepted
- Append IOT_ to all Debug macros (eg. DEBUG is now IOT_DEBUG)
- Fixed exit on error for subscribe_publish_sample
@@ -134,7 +134,7 @@ Bugfixes/Improvements:
- Removed Paho Wrapper, Merge MQTT into SDK code, added specific error codes
- Refactored Network and Timer layer wrappers, added specific error codes
- Refactored samples and makefiles
## [1.1.2](https://github.com/aws/aws-iot-device-sdk-embedded-C/releases/tag/v1.1.2) (April 22, 2016)
Bugfixes/Improvements:
@@ -149,13 +149,13 @@ Bugfixes/Improvements:
- Removing the Executable bit from all the files in the repository. Fixing [this](https://github.com/aws/aws-iot-device-sdk-embedded-C/issues/14) issue
- Refactoring MQTT client to remove declaration after statement warnings
- Fixing [this](https://forums.aws.amazon.com/thread.jspa?threadID=222467&tstart=0) bug
## [1.1.0](https://github.com/aws/aws-iot-device-sdk-embedded-C/releases/tag/v1.1.0) (February 10, 2016)
Features:
- Auto Reconnect and Resubscribe
Bugfixes/Improvements:
- MQTT buffer handling incase of bigger message
@@ -169,7 +169,7 @@ Bugfixes/Improvements:
Bugfixes/Improvements:
- Paho name changed to Eclipse Paho
- Renamed the Makefiles in the samples directory
- Renamed the Makefiles in the samples directory
- Device Shadow - Delete functionality macro fixed
- `subscribe_publish_sample` updated
@@ -182,7 +182,7 @@ Features:
Bugfixes/Improvements:
- Updated API documentation
## 0.4.0 (October 5, 2015)
Features:
@@ -191,7 +191,7 @@ Features:
- aws_iot_config.h file for easy configuration of parameters
- Sample app for talking with console's Interactive guide
- disconnect handler for the MQTT client library
Bugfixes/Improvements:
- mbedTLS read times out every 10 ms instead of hanging for ever
@@ -31,7 +31,7 @@ IOT_CLIENT_DIR = .
APP_DIR = $(IOT_CLIENT_DIR)/tests/unit
APP_NAME = aws_iot_sdk_unit_tests
APP_SRC_FILES = $(shell find $(APP_DIR)/src -name '*.cpp')
APP_SRC_FILES = $(shell find $(APP_DIR)/src -name '*.c')
APP_SRC_FILES += $(shell find $(APP_DIR)/src -name '*.c')
APP_INCLUDE_DIRS = -I $(APP_DIR)/include
CPPUTEST_DIR = $(IOT_CLIENT_DIR)/external_libs/CppUTest
@@ -15,8 +15,8 @@ Current SDK Directory Layout (mbedTLS)
|--`include` (Header files of the AWS IoT device SDK) <br>
|--`src` (Source files of the AWS IoT device SDK) <br>
|--`platform` (Platform specific files) <br>
|--`samples` (Samples including makefiles for building on mbedTLS) <br>
|--`tests` (Tests for verifying SDK is functioning as expected) <br>
|--`samples` (Samples including makefiles for building on mbedTLS) <br>
|--`tests` (Tests for verifying SDK is functioning as expected) <br>
All makefiles in this SDK were configured using the documented folder structure above, so moving or renaming folders will require modifications to makefiles.
@@ -44,7 +44,7 @@ This section explains the API calls that need to be implemented in order for the
### Timer Functions
A timer implementation is necessary to handle request timeouts (sending MQTT connect, subscribe, etc. commands) as well as connection maintenance (MQTT keep-alive pings). Timers need millisecond resolution and are polled for expiration so these can be implemented using a "milliseconds since startup" free-running counter if desired. In the synchronous sample provided with this SDK only one command will be "in flight" at one point in time plus the client's ping timer.
A timer implementation is necessary to handle request timeouts (sending MQTT connect, subscribe, etc. commands) as well as connection maintenance (MQTT keep-alive pings). Timers need millisecond resolution and are polled for expiration so these can be implemented using a "milliseconds since startup" free-running counter if desired. In the synchronous sample provided with this SDK only one command will be "in flight" at one point in time plus the client's ping timer.
Define the `Timer` Struct as in `timer_platform.h`
@@ -63,10 +63,13 @@ countdown_sec - set the timer to expire in x seconds and start the timer.
`uint32_t left_ms(Timer *);`
left_ms - query time in milliseconds left on the timer.
`void delay(unsigned milliseconds)`
delay - sleep for the specified number of milliseconds.
### Network Functions
In order for the MQTT client stack to be able to communicate via the TCP/IP network protocol stack using a mutually authenticated TLS connection, the following API calls need to be implemented for your platform.
In order for the MQTT client stack to be able to communicate via the TCP/IP network protocol stack using a mutually authenticated TLS connection, the following API calls need to be implemented for your platform.
For additional details about API parameters refer to the [API documentation](http://aws-iot-device-sdk-embedded-c-docs.s3-website-us-east-1.amazonaws.com/index.html).
@@ -76,7 +79,7 @@ This is used for data specific to the TLS library being used.
`IoT_Error_t iot_tls_init(Network *pNetwork, char *pRootCALocation, const char *pDeviceCertLocation,
const char *pDevicePrivateKeyLocation, const char *pDestinationURL,
uint16_t DestinationPort, uint32_t timeout_ms, bool ServerVerificationFlag);`
Initialize the network client / structure.
Initialize the network client / structure.
`IoT_Error_t iot_tls_connect(Network *pNetwork, TLSConnectParams *TLSParams);`
Create a TLS TCP socket to the configure address using the credentials provided via the NewNetwork API call. This will include setting up certificate locations / arrays.
@@ -102,7 +105,7 @@ The TLS library generally provides the API for the underlying TCP socket.
### Threading Functions
The MQTT client uses a state machine to control operations in multi-threaded situations. However it requires a mutex implementation to guarantee thread safety. This is not required in situations where thread safety is not important and it is disabled by default. The _ENABLE_THREAD_SUPPORT_ macro needs to be defined in aws_iot_config.h to enable this layer. You will also need to add the -lpthread linker flag for the compiler if you are using the provided reference implementation.
The MQTT client uses a state machine to control operations in multi-threaded situations. However it requires a mutex implementation to guarantee thread safety. This is not required in situations where thread safety is not important and it is disabled by default. The _ENABLE_THREAD_SUPPORT_ macro needs to be defined in aws_iot_config.h to enable this layer. You will also need to add the -lpthread linker flag for the compiler if you are using the provided reference implementation.
For additional details about API parameters refer to the [API documentation](http://aws-iot-device-sdk-embedded-c-docs.s3-website-us-east-1.amazonaws.com/index.html).
@@ -110,7 +113,7 @@ Define the `IoT_Mutex_t` Struct as in `threads_platform.h`
This is used for data specific to the TLS library being used.
`IoT_Error_t aws_iot_thread_mutex_init(IoT_Mutex_t *);`
Initialize the mutex provided as argument.
Initialize the mutex provided as argument.
`IoT_Error_t aws_iot_thread_mutex_lock(IoT_Mutex_t *);`
Lock the mutex provided as argument
@@ -123,11 +126,6 @@ Destroy the mutex provided as argument.
The threading layer provides the implementation of mutexes used for thread-safe operations.
### Sample Porting:
Marvell has ported the SDK for their development boards. [These](https://github.com/marvell-iot/aws_starter_sdk/tree/master/sdk/external/aws_iot/platform/wmsdk) files are example implementations of the above mentioned functions.
This provides a port of the timer and network layer. The threading layer is not a part of this port.
## Time source for certificate validation
As part of the TLS handshake the device (client) needs to validate the server certificate which includes validation of the certificate lifetime requiring that the device is aware of the actual time. Devices should be equipped with a real time clock or should be able to obtain the current time via NTP. Bypassing validation of the lifetime of a certificate is not recommended as it exposes the device to a security vulnerability, as it will still accept server certificates even when they have already has_timer_expired.
@@ -140,7 +138,7 @@ The single threaded implementation implies that the sample application code (SDK
### Multi-Threaded implementation
In the simple multi-threaded case the `yield` function can be moved to a background thread. Ensure this task runs at the frequency described above. In this case, depending on the OS mechanism, a message queue or mailbox could be used to proxy incoming MQTT messages from the callback to the worker task responsible for responding to or dispatching messages. A similar mechanism could be employed to queue publish messages from threads into a publish queue that are processed by a publishing task. Ensure the threading layer is enabled as the library is not thread safe otherwise.
There is a validation test for the multi-threaded implementation that can be found with the integration tests. You can find further details in the Readme for the integration tests [here](https://github.com/aws/aws-iot-device-sdk-embedded-C/blob/master/tests/integration/README.md). We have run the validation test with 10 threads sending 500 messages each and verified to be working fine. It can be used as a reference testing application to validate whether your use case will work with multi-threading enabled.
There is a validation test for the multi-threaded implementation that can be found with the integration tests. You can find further details in the Readme for the integration tests [here](https://github.com/aws/aws-iot-device-sdk-embedded-C/blob/master/tests/integration/README.md/). We have run the validation test with 10 threads sending 500 messages each and verified to be working fine. It can be used as a reference testing application to validate whether your use case will work with multi-threading enabled.
## Sample applications
@@ -1,15 +1,23 @@
**We have released version 4.0.0 beta 1 of this SDK on the [v4_beta](https://github.com/aws/aws-iot-device-sdk-embedded-C/tree/v4_beta) branch and encourage everyone to give it a try.**
[![Build Status](https://travis-ci.org/aws/aws-iot-device-sdk-embedded-C.svg?branch=master)](https://travis-ci.org/aws/aws-iot-device-sdk-embedded-C)
Version 4 is a new design, and therefore **NOT** backwards compatible with version 3.0.1. We will continue to fix bugs in v3.0.1 even after v4.0.0 is released, but we may not add new features to v3.0.1.
<a href="https://scan.coverity.com/projects/aws-iot-device-sdk-embedded-c">
<img alt="Coverity Scan Build Status"
src="https://scan.coverity.com/projects/15543/badge.svg"/>
</a>
Please be aware that v4 beta may have bugs and performance issues. Additionally, there are currently missing features compared to v3.0.1. See the [README](https://github.com/aws/aws-iot-device-sdk-embedded-C/blob/v4_beta/README.md/) on the v4_beta branch for more information.
## ***** NOTICE *****
This repository is moving to a new branching system. The master branch will now contain bug fixes/features that have been minimally tested to ensure nothing major is broken. The release branch will contain new releases for the SDK that have been tested thoroughly on all supported platforms. Please ensure that you are tracking the release branch for all production work.
## Branches
This change will allow us to push out bug fixes quickly and avoid having situations where issues stay open for a very long time.
### Master branch
The [master](https://github.com/aws/aws-iot-device-sdk-embedded-C/tree/master) branch will now contain bug fixes/features that have been minimally tested to ensure nothing major is broken. The current version on the master branch is v3.0.1. Eventually, we will move v4.0.0 to the master branch and move v3.0.1 to a legacy branch.
### Release branch
The [release](https://github.com/aws/aws-iot-device-sdk-embedded-C/tree/release) branch will contain new releases for the SDK that have been tested thoroughly on all supported platforms. Please ensure that you are tracking the release branch for all production work. The current version on the release branch is v3.0.1. Eventually, we will move v4.0.0 to the release branch and move v3.0.1 to a legacy branch.
### v4_beta branch
The [v4_beta](https://github.com/aws/aws-iot-device-sdk-embedded-C/tree/v4_beta) branch will contain new features and a new design that inherits from both the AWS IoT Device SDK Embedded C and the libraries provided with Amazon FreeRTOS. This is version 4.0.0 of the SDK. Please be aware that v4 beta may have bugs and performance issues. Eventually, we will move v4.0.0 to the master/release branches and delete v4 beta branch.
### Development branch
The [development](https://github.com/aws/aws-iot-device-sdk-embedded-C/tree/development) currently hosts development of the next iteration of the AWS IoT Embedded C SDK version 4. It is currently a work in progress and should not be used to create any products. We will update this README when that status changes.
## Overview
@@ -35,7 +43,7 @@ Primary aspects are:
* Static memory only (no mallocs)
* Configurable resource usage(JSON tokens, MQTT subscription handlers, etc…)
* Can be ported to a different RTOS, uses wrappers for OS specific functions
For more information on the Architecture of the SDK refer [here](http://aws-iot-device-sdk-embedded-c-docs.s3-website-us-east-1.amazonaws.com/index.html)
## Collection of Metrics
@@ -45,14 +53,14 @@ Beginning with Release v2.2.0 of the SDK, AWS collects usage metrics indicating
## How to get started ?
Ensure you understand the AWS IoT platform and create the necessary certificates and policies. For more information on the AWS IoT platform please visit the [AWS IoT developer guide](http://docs.aws.amazon.com/iot/latest/developerguide/iot-security-identity.html).
In order to quickly get started with the AWS IoT platform, we have ported the SDK for POSIX type Operating Systems like Ubuntu, OS X and RHEL. The SDK is configured for the mbedTLS library and can be built out of the box with *GCC* using *make utility*. You'll need to download mbedTLS from the official ARMmbed repository. We recommend that you pick the latest version in order to have up-to-date security fixes.
In order to quickly get started with the AWS IoT platform, we have ported the SDK for POSIX type Operating Systems like Ubuntu, OS X and RHEL. The SDK is configured for the mbedTLS library and can be built out of the box with *GCC* using *make utility*. You'll need to download mbedTLS from the official ARMmbed repository. We recommend that you pick the latest version of 2.16 LTS release in order to have up-to-date security fixes.
## Installation
This section explains the individual steps to retrieve the necessary files and be able to build your first application using the AWS IoT device SDK for embedded C.
Steps:
* Create a directory to hold your application e.g. (/home/<user>/aws_iot/my_app)
* Create a directory to hold your application e.g. (/home/*user*/aws_iot/my_app)
* Change directory to this new directory
* Download the SDK to device and place in the newly created directory
* Expand the tarball (tar -xf <tarball.tar>). This will create the below directories:
@@ -63,13 +71,13 @@ Steps:
* `platform` - Platform specific files for timer, TLS and threading layers
* `samples` - The sample applications
* `src` - The AWS IoT SDK source files
* `tests` - Contains tests for verifying that the SDK is functioning as expected. More information can be found [here](https://github.com/aws/aws-iot-device-sdk-embedded-c/blob/master/tests/README.md)
* View further information on how to use the SDK in the Readme file for samples that can be found [here](https://github.com/aws/aws-iot-device-sdk-embedded-c/blob/master/samples/README.md)
* `tests` - Contains tests for verifying that the SDK is functioning as expected. More information can be found [here](https://github.com/aws/aws-iot-device-sdk-embedded-c/blob/master/tests/README.md/)
* View further information on how to use the SDK in the README file for samples that can be found [here](https://github.com/aws/aws-iot-device-sdk-embedded-c/blob/master/samples/README.md/)
Also, for a guided example on getting started with the Thing Shadow, visit the AWS IoT Console's [Interactive Guide](https://console.aws.amazon.com/iot).
## Porting to different platforms
As Embedded devices run on different Real Time Operating Systems and TCP/IP stacks, it is one of the important design goals for the Device SDK to keep it portable. Please refer to the [porting guide](https://github.com/aws/aws-iot-device-sdk-embedded-C/blob/master/PortingGuide.md) to get more information on how to make this SDK run on your devices (i.e. micro-controllers).
As Embedded devices run on different real-time operating systems and TCP/IP stacks, it is one of the important design goals for the Device SDK to keep it portable. Please refer to the [porting guide](https://github.com/aws/aws-iot-device-sdk-embedded-C/blob/master/PortingGuide.md/) to get more information on how to make this SDK run on your devices (i.e. microcontrollers).
## Migrating from 1.x to 2.x
The 2.x branch makes several changes to the SDK. This section provides information on what changes will be required in the client application for migrating from v1.x to 2.x.
@@ -78,7 +86,7 @@ The 2.x branch makes several changes to the SDK. This section provides informati
* All the SDK headers are in the `include` folder. These need to be added to the makefile as include directories
* The source files are in the `src` folder. These need to be added to the makefile as one of the source directories
* Similar to 1.x, the platform folder contains the platform specific headers and source files. These need to be added to the makefile as well
* The `platform/threading` folder only needs to be added if multi-threading is required, and the `_ENABLE_THREAD_SUPPORT_` macro is defined in config
* The `platform/threading` folder only needs to be added if multi-threading is required, and the `_ENABLE_THREAD_SUPPORT_` macro is defined in config
* The list below provides a mapping for migrating from the major APIs used in 1.x to the new APIs:
| Description | 1.x | 2.x |
@@ -91,7 +99,7 @@ The 2.x branch makes several changes to the SDK. This section provides informati
| Publish | ```IoT_Error_t aws_iot_mqtt_publish(MQTTPublishParams *pParams);``` | ```IoT_Error_t aws_iot_mqtt_publish(AWS_IoT_Client *pClient, const char *pTopicName, uint16_t topicNameLen, IoT_Publish_Message_Params *pParams);``` |
| Disconnect | ```IoT_Error_t aws_iot_mqtt_disconnect(void);``` | ```IoT_Error_t aws_iot_mqtt_disconnect(AWS_IoT_Client *pClient);``` |
You can find more information on how to use the new APIs in the Readme file for samples that can be found [here](https://github.com/aws/aws-iot-device-sdk-embedded-c/blob/master/samples/README.md)
You can find more information on how to use the new APIs in the README file for samples that can be found [here](https://github.com/aws/aws-iot-device-sdk-embedded-c/blob/master/samples/README.md/)
## Migrating from 2.x to 3.x
AWS IoT Device SDK for Embedded C v3.0.0 fixes two bugs (see #152 and #155) that create a potential buffer overflows. This version is not backward compatible with previous versions, so users will need to recompile their applications with the new version.
@@ -129,7 +137,7 @@ exampleJsonStruct.type = SHADOW_JSON_INT32;
exampleJsonStruct.cb = exampleCallback;
/* Register a delta callback using example JsonStruct. */
aws_iot_shadow_register_delta(&mqttClient, &exampleJsonStruct);
aws_iot_shadow_register_delta(&mqttClient, &exampleJsonStruct);
```
@@ -222,11 +230,11 @@ Version 3.0.0 changes the signature of four functions intended for internal usag
#### Old signatures:
```c
bool extractClientToken(const char *pJsonDocument, char *pExtractedClientToken);
bool extractClientToken(const char *pJsonDocument, char *pExtractedClientToken);
static void emptyJsonWithClientToken(char *pBuffer);
bool isJsonValidAndParse(const char *pJsonDocument, void *pJsonHandler, int32_t *pTokenCount);
bool isJsonValidAndParse(const char *pJsonDocument, void *pJsonHandler, int32_t *pTokenCount);
bool isReceivedJsonValid(const char *pJsonDocument);
```
@@ -234,7 +242,7 @@ bool isReceivedJsonValid(const char *pJsonDocument);
#### New signatures:
```c
bool extractClientToken(const char *pJsonDocument, size_t jsonSize, char *pExtractedClientToken, size_t clientTokenSize);
bool extractClientToken(const char *pJsonDocument, size_t jsonSize, char *pExtractedClientToken, size_t clientTokenSize);
static void emptyJsonWithClientToken(char *pBuffer, size_t bufferSize);
@@ -272,7 +280,7 @@ rc = aws_iot_mqtt_subscribe(&client, "sdkTest/sub", 11, QOS0, iot_subscribe_call
Update Thing Shadow from a device
```
```
rc = aws_iot_shadow_update(&mqttClient, AWS_IOT_MY_THING_NAME, pJsonDocumentBuffer, ShadowUpdateStatusCallback,
pCallbackContext, TIMEOUT_4SEC, persistenSubscription);
```
@@ -1,5 +1,5 @@
# Copy source code for mbedTLS into this directory
#
# You'll need to download mbedTLS from the official ARMmbed repository and
# place the files here. We recommend that you pick the latest version in
# order to have up-to-date security fixes.
# place the files here. We recommend that you pick the latest version of 2.16
# LTS release in order to have up-to-date security fixes.
@@ -61,6 +61,7 @@ extern "C" {
#include "threads_interface.h"
#endif
/** Greatest packet identifier, per MQTT spec */
#define MAX_PACKET_ID 65535
typedef struct _Client AWS_IoT_Client;
@@ -118,8 +119,10 @@ typedef struct {
bool isRetained; ///< NOT supported. The retained flag for the LWT message (see MQTTAsync_message.retained)
QoS qos; ///< QoS of LWT message
} IoT_MQTT_Will_Options;
/** Default initializer for will */
extern const IoT_MQTT_Will_Options iotMqttWillOptionsDefault;
/** Default initializer for will */
#define IoT_MQTT_Will_Options_Initializer { {'M', 'Q', 'T', 'W'}, NULL, 0, NULL, 0, false, QOS0 }
/**
@@ -142,8 +145,10 @@ typedef struct {
char *pPassword; ///< Not used in the AWS IoT Service, will need to be cstring if used
uint16_t passwordLen; ///< Password Length. 16 bit unsigned integer
} IoT_Client_Connect_Params;
/** Default initializer for connect */
extern const IoT_Client_Connect_Params iotClientConnectParamsDefault;
/** Default initializer for connect */
#define IoT_Client_Connect_Params_initializer { {'M', 'Q', 'T', 'C'}, MQTT_3_1_1, NULL, 0, 60, true, false, \
IoT_MQTT_Will_Options_Initializer, NULL, 0, NULL, 0 }
@@ -179,8 +184,10 @@ typedef struct {
bool isBlockOnThreadLockEnabled; ///< Timeout for Thread blocking calls. Set to 0 to block until lock is obtained. In milliseconds
#endif
} IoT_Client_Init_Params;
/** Default initializer for client */
extern const IoT_Client_Init_Params iotClientInitParamsDefault;
/** Default initializer for client */
#ifdef _ENABLE_THREAD_SUPPORT_
#define IoT_Client_Init_Params_initializer { true, NULL, 0, NULL, NULL, NULL, 2000, 20000, 5000, true, NULL, NULL, false }
#else
@@ -228,11 +235,12 @@ typedef void (*pApplicationHandler_t)(AWS_IoT_Client *pClient, char *pTopicName,
*
*/
typedef struct _MessageHandlers {
const char *topicName;
uint16_t topicNameLen;
QoS qos;
pApplicationHandler_t pApplicationHandler;
void *pApplicationHandlerData;
const char *topicName; ///< Topic name of subscription
uint16_t topicNameLen; ///< Length of topic name
char resubscribed; ///< Whether this handler was successfully resubscribed in the reconnect workflow
QoS qos; ///< QoS of subscription
pApplicationHandler_t pApplicationHandler; ///< Application function to invoke
void *pApplicationHandlerData; ///< Context to pass to application handler
} MessageHandlers; /* Message handlers are indexed by subscription topic */
/**
@@ -243,9 +251,9 @@ typedef struct _MessageHandlers {
*
*/
typedef struct _ClientStatus {
ClientState clientState;
bool isPingOutstanding;
bool isAutoReconnectEnabled;
ClientState clientState; ///< The current state of the client's state machine
bool isPingOutstanding; ///< Whether this client is waiting for a ping response
bool isAutoReconnectEnabled; ///< Whether auto-reconnect is enabled for this client
} ClientStatus;
/**
@@ -256,36 +264,35 @@ typedef struct _ClientStatus {
*
*/
typedef struct _ClientData {
uint16_t nextPacketId;
uint16_t nextPacketId; ///< Packet ID to use for the next generated packet
uint32_t packetTimeoutMs;
uint32_t commandTimeoutMs;
uint16_t keepAliveInterval;
uint32_t currentReconnectWaitInterval;
uint32_t counterNetworkDisconnected;
uint32_t packetTimeoutMs; ///< Timeout for reading incoming packets from the network
uint32_t commandTimeoutMs; ///< Timeout for processing outgoing MQTT packets
uint16_t keepAliveInterval; ///< Maximum interval between control packets
uint32_t currentReconnectWaitInterval; ///< Current backoff period for reconnect
uint32_t counterNetworkDisconnected; ///< How many times this client detected a disconnection
/* The below values are initialized with the
* lengths of the TX/RX buffers and never modified
* afterwards */
size_t writeBufSize;
size_t readBufSize;
size_t readBufIndex;
unsigned char writeBuf[AWS_IOT_MQTT_TX_BUF_LEN];
unsigned char readBuf[AWS_IOT_MQTT_RX_BUF_LEN];
size_t writeBufSize; ///< Size of this client's outgoing data buffer
size_t readBufSize; ///< Size of this client's incoming data buffer
size_t readBufIndex; ///< Current offset into the incoming data buffer
unsigned char writeBuf[AWS_IOT_MQTT_TX_BUF_LEN]; ///< Buffer for outgoing data
unsigned char readBuf[AWS_IOT_MQTT_RX_BUF_LEN]; ///< Buffer for incoming data
#ifdef _ENABLE_THREAD_SUPPORT_
bool isBlockOnThreadLockEnabled;
IoT_Mutex_t state_change_mutex;
IoT_Mutex_t tls_read_mutex;
IoT_Mutex_t tls_write_mutex;
bool isBlockOnThreadLockEnabled; ///< Whether to use nonblocking or blocking mutex APIs
IoT_Mutex_t state_change_mutex; ///< Mutex protecting the client's state machine
IoT_Mutex_t tls_read_mutex; ///< Mutex protecting incoming data
IoT_Mutex_t tls_write_mutex; ///< Mutex protecting outgoing data
#endif
IoT_Client_Connect_Params options;
IoT_Client_Connect_Params options; ///< Options passed when the client was initialized
MessageHandlers messageHandlers[AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS];
iot_disconnect_handler disconnectHandler;
void *disconnectHandlerData;
MessageHandlers messageHandlers[AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS]; ///< Callbacks for incoming messages
iot_disconnect_handler disconnectHandler; ///< Callback when a disconnection is detected
void *disconnectHandlerData; ///< Context for disconnect handler
} ClientData;
/**
@@ -295,121 +302,186 @@ typedef struct _ClientData {
*
*/
struct _Client {
Timer pingTimer;
Timer reconnectDelayTimer;
Timer pingReqTimer; ///< Timer to keep track of when to send next PINGREQ
Timer pingRespTimer; ///< Timer to ensure that PINGRESP is received timely
Timer reconnectDelayTimer; ///< Timer for backoff on reconnect
ClientStatus clientStatus;
ClientData clientData;
Network networkStack;
ClientStatus clientStatus; ///< Client state information
ClientData clientData; ///< Client context
Network networkStack; ///< Table of network function pointers
};
/**
* @brief What is the next available packet Id
*
* Called to retrieve the next packet id to be used for outgoing packets.
* Automatically increments the last sent packet id variable
*
* @param pClient Reference to the IoT Client
*
* @return next packet id as a 16 bit unsigned integer
* @functionpage{aws_iot_mqtt_get_next_packet_id,mqtt,get_next_packet_id}
* @functionpage{aws_iot_mqtt_set_connect_params,mqtt,set_connect_params}
* @functionpage{aws_iot_mqtt_is_client_connected,mqtt,is_client_connected}
* @functionpage{aws_iot_mqtt_get_client_state,mqtt,get_client_state}
* @functionpage{aws_iot_is_autoreconnect_enabled,mqtt,is_autoreconnect_enabled}
* @functionpage{aws_iot_mqtt_set_disconnect_handler,mqtt,set_disconnect_handler}
* @functionpage{aws_iot_mqtt_autoreconnect_set_status,mqtt,autoreconnect_set_status}
* @functionpage{aws_iot_mqtt_get_network_disconnected_count,mqtt,get_network_disconnected_count}
* @functionpage{aws_iot_mqtt_reset_network_disconnected_count,mqtt,reset_network_disconnected_count}
*/
/**
* @brief Retrieve and increment the next packet identifier for an MQTT client context.
*
* This function generates a two-byte packet identifier for an outgoing MQTT packet and
* modifies the internal state of the MQTT client context so that the next call generates
* a different packet identifier. Per the MQTT specification, MQTT packet identifiers are
* nonzero, two-byte integers that identify certain MQTT packets. MQTT packet identifiers
* must be unique at any given time: no two concurrent packets may use the same identifier,
* but packet identifiers from previously processed packets may be reused.
*
* @param[in] pClient MQTT client context
*
* @return A two-byte MQTT packet identifier that will be unique for the given MQTT client
* context.
*
* @warning This function is not thread safe. Do not call it concurrently from different
* threads.
*/
/* @[declare_mqtt_get_next_packet_id] */
uint16_t aws_iot_mqtt_get_next_packet_id(AWS_IoT_Client *pClient);
/* @[declare_mqtt_get_next_packet_id] */
/**
* @brief Set the connection parameters for the IoT Client
* @brief Reset the connection parameters of an initialized MQTT client context.
*
* Called to set the connection parameters for the IoT Client.
* Used to update the connection parameters provided before the last connect.
* Won't take effect until the next time connect is called
* This function replaces the current connection parameters of an MQTT client
* context with a new set of parameters. Its primary use is to modify the connection
* parameters for the next reconnect attempt if the existing parameters are no longer
* valid. Therefore, it should be called just before a reconnect attempt, i.e. just
* before @ref mqtt_function_attempt_reconnect or @ref mqtt_function_yield.
*
* @param pClient Reference to the IoT Client
* @param pNewConnectParams Reference to the new Connection Parameters structure
* The new connection parameters take effect at the next connection attempt.
*
* @return IoT_Error_t Type defining successful/failed API call
* @param[in] pClient MQTT client context
* @param[in] pNewConnectParams The new connection parameters
*
* @return Returns NULL_VALUE_ERROR if provided a bad parameter; otherwise, always
* returns SUCCESS.
*
* @warning Do not call this function if a connection attempt is in progress. Connection
* attempts happen in the context of @ref mqtt_function_connect, @ref mqtt_function_attempt_reconnect,
* or @ref mqtt_function_yield.
*/
/* @[declare_mqtt_set_connect_params] */
IoT_Error_t aws_iot_mqtt_set_connect_params(AWS_IoT_Client *pClient, const IoT_Client_Connect_Params *pNewConnectParams);
/* @[declare_mqtt_set_connect_params] */
/**
* @brief Is the MQTT client currently connected?
* @brief Determine if the MQTT client context currently connected to a server.
*
* Called to determine if the MQTT client is currently connected. Used to support logic
* in the device application around reconnecting and managing offline state.
* This function checks the internal state of the MQTT client context to determine
* if it is currently connected to the server.
*
* @param pClient Reference to the IoT Client
* @param[in] pClient MQTT client context
*
* @return true = connected, false = not currently connected
* @return true if connected; false otherwise.
*
* @warning Application code should not rely on this function's return value.
* The returned value only represents the internal state of the client and
* does not check the network connection status.
*/
/* @[declare_mqtt_is_client_connected] */
bool aws_iot_mqtt_is_client_connected(AWS_IoT_Client *pClient);
/* @[declare_mqtt_is_client_connected] */
/**
* @brief Get the current state of the client
* @brief Get the current state of the MQTT client context.
*
* Called to get the current state of the client
* @param[in] pClient MQTT client context
*
* @param pClient Reference to the IoT Client
* @return The state of the MQTT client context at the time of the function call.
*
* @return ClientState value equal to the current state of the client
* @note The client's state is internal and generally not useful to application code.
* Applications should not make assumptions about the status of the client based on
* its state.
*/
/* @[declare_mqtt_get_client_state] */
ClientState aws_iot_mqtt_get_client_state(AWS_IoT_Client *pClient);
/* @[declare_mqtt_get_client_state] */
/**
* @brief Is the MQTT client set to reconnect automatically?
* @brief Determine if auto-reconnect is enabled for an MQTT client context.
*
* Called to determine if the MQTT client is set to reconnect automatically.
* Used to support logic in the device application around reconnecting
* @param[in] pClient MQTT client context
*
* @param pClient Reference to the IoT Client
*
* @return true = enabled, false = disabled
* @return true if auto-reconnect is enabled; false otherwise.
*/
/* @[declare_mqtt_is_autoreconnect_enabled] */
bool aws_iot_is_autoreconnect_enabled(AWS_IoT_Client *pClient);
/* @[declare_mqtt_is_autoreconnect_enabled] */
/**
* @brief Set the IoT Client disconnect handler
* @brief Reset the disconnect handler of an initialized MQTT client context.
*
* Called to set the IoT Client disconnect handler
* The disconnect handler is called whenever the client disconnects with error
* This function replaces the current disconnect handler of an MQTT client
* context with a new disconnect handler.
*
* @param pClient Reference to the IoT Client
* @param pConnectHandler Reference to the new Disconnect Handler
* @param pDisconnectHandlerData Reference to the data to be passed as argument when disconnect handler is called
* The new disconnect handler will be invoked when the next disconnect is detected.
*
* @return IoT_Error_t Type defining successful/failed API call
* @param[in] pClient MQTT client context
* @param[in] pDisconnectHandler New disconnect handler
* @param[in] pDisconnectHandlerData Context to be passed to new disconnect handler
*
* @return Returns NULL_VALUE_ERROR if provided a bad parameter; otherwise, always
* returns SUCCESS.
*
* @warning Do not call this function if @ref mqtt_function_yield is in progress.
*/
/* @[declare_mqtt_set_disconnect_handler] */
IoT_Error_t aws_iot_mqtt_set_disconnect_handler(AWS_IoT_Client *pClient, iot_disconnect_handler pDisconnectHandler,
void *pDisconnectHandlerData);
/* @[declare_mqtt_set_disconnect_handler] */
/**
* @brief Enable or Disable AutoReconnect on Network Disconnect
* @brief Enable or disable auto-reconnect for an initialized MQTT client context.
*
* Called to enable or disabled the auto reconnect features provided with the SDK
* This function replaces the current auto-reconnect setting with the provided setting.
*
* @param pClient Reference to the IoT Client
* @param newStatus set to true for enabling and false for disabling
* @note This function should only be called after @ref mqtt_function_connect has been
* called for the provided client.
*
* @return IoT_Error_t Type defining successful/failed API call
* @param[in] pClient MQTT client context
* @param[in] newStatus New setting for auto-reconnect
*
* @return Returns NULL_VALUE_ERROR if provided a bad parameter; otherwise, always
* returns SUCCESS.
*
* @warning Do not call this function if a connection attempt is in progress. Connection
* attempts happen in the context of @ref mqtt_function_connect, @ref mqtt_function_attempt_reconnect,
* or @ref mqtt_function_yield.
*/
/* @[declare_mqtt_autoreconnect_set_status] */
IoT_Error_t aws_iot_mqtt_autoreconnect_set_status(AWS_IoT_Client *pClient, bool newStatus);
/* @[declare_mqtt_autoreconnect_set_status] */
/**
* @brief Get count of Network Disconnects
* @brief Get the current number of disconnects detected by an MQTT client context.
*
* Called to get the number of times a network disconnect occurred due to errors
* @param[in] pClient MQTT client context
*
* @param pClient Reference to the IoT Client
* @return The number of disconnects detected since the client was created
* (or since the last call to @ref mqtt_function_reset_network_disconnected_count).
*
* @return uint32_t the disconnect count
* @warning Do not call this function if @ref mqtt_function_yield is in progress.
*/
/* @[declare_mqtt_get_network_disconnected_count] */
uint32_t aws_iot_mqtt_get_network_disconnected_count(AWS_IoT_Client *pClient);
/* @[declare_mqtt_get_network_disconnected_count] */
/**
* @brief Reset Network Disconnect conter
* @brief Reset the number of disconnects detected by an MQTT client context to zero.
*
* Called to reset the Network Disconnect counter to zero
* @param[in] pClient MQTT client context
*
* @param pClient Reference to the IoT Client
* @warning Do not call this function if @ref mqtt_function_yield is in progress.
*/
/* @[declare_mqtt_reset_network_disconnected_count] */
void aws_iot_mqtt_reset_network_disconnected_count(AWS_IoT_Client *pClient);
/* @[declare_mqtt_reset_network_disconnected_count] */
#ifdef __cplusplus
}
@@ -49,7 +49,7 @@ extern "C" {
#include "aws_iot_mqtt_client_interface.h"
/* Enum order should match the packet ids array defined in MQTTFormat.c */
/** Types of MQTT messages */
typedef enum msgTypes {
UNKNOWN = -1,
CONNECT = 1,
@@ -69,10 +69,10 @@ typedef enum msgTypes {
} MessageTypes;
/* Macros for parsing header fields from incoming MQTT frame. */
#define MQTT_HEADER_FIELD_TYPE(_byte) ((_byte >> 4) & 0x0F)
#define MQTT_HEADER_FIELD_DUP(_byte) ((_byte & (1 << 3)) >> 3)
#define MQTT_HEADER_FIELD_QOS(_byte) ((_byte & (3 << 1)) >> 1)
#define MQTT_HEADER_FIELD_RETAIN(_byte) ((_byte & (1 << 0)) >> 0)
#define MQTT_HEADER_FIELD_TYPE(_byte) ((_byte >> 4) & 0x0F) /**< Message type */
#define MQTT_HEADER_FIELD_DUP(_byte) ((_byte & (1 << 3)) >> 3) /**< DUP flag */
#define MQTT_HEADER_FIELD_QOS(_byte) ((_byte & (3 << 1)) >> 1) /**< QoS */
#define MQTT_HEADER_FIELD_RETAIN(_byte) ((_byte & (1 << 0)) >> 0) /**< Retain flag */
/**
* Bitfields for the MQTT header byte.
@@ -32,7 +32,7 @@
*******************************************************************************/
/**
* @file aws_iot_mqtt_interface.h
* @file aws_iot_mqtt_client_interface.h
* @brief Interface definition for MQTT client.
*/
@@ -58,153 +58,245 @@ extern "C" {
#include "network_interface.h"
#include "timer_interface.h"
/**
* @brief Clean mqtt client from all dynamic memory allocate
*
* This function will free up memory that was dynamically allocated for the client.
*
* @param pClient MQTT Client that was previously created by calling aws_iot_mqtt_init
* @return An IoT Error Type defining successful/failed freeing
*/
IoT_Error_t aws_iot_mqtt_free( AWS_IoT_Client *pClient );
/**
* @brief MQTT Client Initialization Function
* @functionspage{mqtt,MQTT library}
*
* Called to initialize the MQTT Client
*
* @param pClient Reference to the IoT Client
* @param pInitParams Pointer to MQTT connection parameters
*
* @return IoT_Error_t Type defining successful/failed API call
* API functions
* - @functionname{mqtt_function_init}
* - @functionname{mqtt_function_free}
* - @functionname{mqtt_function_connect}
* - @functionname{mqtt_function_publish}
* - @functionname{mqtt_function_subscribe}
* - @functionname{mqtt_function_resubscribe}
* - @functionname{mqtt_function_unsubscribe}
* - @functionname{mqtt_function_disconnect}
* - @functionname{mqtt_function_yield}
* - @functionname{mqtt_function_attempt_reconnect}
* - @functionname{mqtt_function_get_next_packet_id}
* - @functionname{mqtt_function_set_connect_params}
* - @functionname{mqtt_function_is_client_connected}
* - @functionname{mqtt_function_get_client_state}
* - @functionname{mqtt_function_is_autoreconnect_enabled}
* - @functionname{mqtt_function_set_disconnect_handler}
* - @functionname{mqtt_function_autoreconnect_set_status}
* - @functionname{mqtt_function_get_network_disconnected_count}
* - @functionname{mqtt_function_reset_network_disconnected_count}
*/
/**
* @functionpage{aws_iot_mqtt_init,mqtt,init}
* @functionpage{aws_iot_mqtt_free,mqtt,free}
* @functionpage{aws_iot_mqtt_connect,mqtt,connect}
* @functionpage{aws_iot_mqtt_publish,mqtt,publish}
* @functionpage{aws_iot_mqtt_subscribe,mqtt,subscribe}
* @functionpage{aws_iot_mqtt_resubscribe,mqtt,resubscribe}
* @functionpage{aws_iot_mqtt_unsubscribe,mqtt,unsubscribe}
* @functionpage{aws_iot_mqtt_disconnect,mqtt,disconnect}
* @functionpage{aws_iot_mqtt_yield,mqtt,yield}
* @functionpage{aws_iot_mqtt_attempt_reconnect,mqtt,attempt_reconnect}
*/
/**
* @brief Initialize a new MQTT client context.
*
* This function should be called before any other MQTT function to initialize
* a new MQTT client context. Once the client context is no longer needed,
* @ref mqtt_function_free should be called.
*
* @param[in] pClient MQTT client context to initialize
* @param[in] pInitParams The MQTT connection parameters
*
* @return `IoT_Error_t`: See `aws_iot_error.h`
*/
/* @[declare_mqtt_init] */
IoT_Error_t aws_iot_mqtt_init(AWS_IoT_Client *pClient, const IoT_Client_Init_Params *pInitParams);
/* @[declare_mqtt_init] */
/**
* @brief MQTT Connection Function
* @brief Clean up an MQTT client context that is no longer needed.
*
* Called to establish an MQTT connection with the AWS IoT Service
* This function will free up resources used by an MQTT client context. It should
* only be called when that context is no longer needed.
*
* @param pClient Reference to the IoT Client
* @param pConnectParams Pointer to MQTT connection parameters
* @param[in] pClient MQTT client context that was previously initialized by
* @ref mqtt_function_init
*
* @return An IoT Error Type defining successful/failed connection
* @return `IoT_Error_t`: See `aws_iot_error.h`
*/
/* @[declare_mqtt_free] */
IoT_Error_t aws_iot_mqtt_free( AWS_IoT_Client *pClient );
/* @[declare_mqtt_free] */
/**
* @brief Establish a connection with an MQTT server.
*
* This function should be called once and after @ref mqtt_function_init. It sends
* the MQTT CONNECT packet to the server, which establishes an MQTT session. Once
* the session is no longer needed, it can be closed with @ref mqtt_function_disconnect.
*
* @param[in] pClient MQTT client context
* @param[in] pConnectParams MQTT connection parameters
*
* @return `IoT_Error_t`: See `aws_iot_error.h`
*/
/* @[declare_mqtt_connect] */
IoT_Error_t aws_iot_mqtt_connect(AWS_IoT_Client *pClient, const IoT_Client_Connect_Params *pConnectParams);
/* @[declare_mqtt_connect] */
/**
* @brief Publish an MQTT message on a topic
* @brief Publish an MQTT message to a topic.
*
* Called to publish an MQTT message on a topic.
* @note Call is blocking. In the case of a QoS 0 message the function returns
* after the message was successfully passed to the TLS layer. In the case of QoS 1
* the function returns after the receipt of the PUBACK control packet.
* This function sends an MQTT message to the server. The server will then
* forward this message to any clients with subscriptions to topic filters
* that match the message's topic.
*
* @param pClient Reference to the IoT Client
* @param pTopicName Topic Name to publish to
* For a QoS 0 message, this function returns after the message is successfully
* passed to the TLS layer. For a QoS 1 message, this function returns after the
* receipt of the PUBACK for the transmitted message.
*
* @param pClient MQTT client context
* @param pTopicName Topic name to publish to
* @param topicNameLen Length of the topic name
* @param pParams Pointer to Publish Message parameters
* @param pParams Publish message parameters
*
* @return An IoT Error Type defining successful/failed publish
* @return `IoT_Error_t`: See `aws_iot_error.h`
*/
/* @[declare_mqtt_publish] */
IoT_Error_t aws_iot_mqtt_publish(AWS_IoT_Client *pClient, const char *pTopicName, uint16_t topicNameLen,
IoT_Publish_Message_Params *pParams);
/* @[declare_mqtt_publish] */
/**
* @brief Subscribe to an MQTT topic.
*
* Called to send a subscribe message to the broker requesting a subscription
* to an MQTT topic.
* @note Call is blocking. The call returns after the receipt of the SUBACK control packet.
* @warning pTopicName and pApplicationHandlerData need to be static in memory.
* This function sends an MQTT subscribe packet to the server. It registers
* a subscription that will cause the provided callback function to be invoked
* when the server sends a message on a matching topic to the client.
*
* @param pClient Reference to the IoT Client
* @param pTopicName Topic Name to publish to. pTopicName needs to be static in memory since
* no malloc are performed by the SDK
* @param topicNameLen Length of the topic name
* @param pApplicationHandler_t Reference to the handler function for this subscription
* @param pApplicationHandlerData Point to data passed to the callback.
* pApplicationHandlerData also needs to be static in memory since no malloc are performed by the SDK
* @note Incoming messages are handled by @ref mqtt_function_yield. Therefore,
* @ref mqtt_function_yield must always be called regularly if any subscriptions
* are active.
*
* @return An IoT Error Type defining successful/failed subscription
* @param[in] pClient MQTT client context
* @param[in] pTopicName Topic for subscription
* @param[in] topicNameLen Length of topic
* @param[in] qos Quality of service for subscription
* @param[in] pApplicationHandler Callback function for incoming messages that arrive
* on this subscription
* @param[in] pApplicationHandlerData Data passed to the callback
*
* @return `IoT_Error_t`: See `aws_iot_error.h`
*
* @attention The `pTopicName` parameter is not copied. It must remain valid for the duration
* of the subscription (until @ref mqtt_function_unsubscribe) is called.
*/
/* @[declare_mqtt_subscribe] */
IoT_Error_t aws_iot_mqtt_subscribe(AWS_IoT_Client *pClient, const char *pTopicName, uint16_t topicNameLen,
QoS qos, pApplicationHandler_t pApplicationHandler, void *pApplicationHandlerData);
/* @[declare_mqtt_subscribe] */
/**
* @brief Subscribe to an MQTT topic.
* @brief Resubscribe to topic filter subscriptions in a previous MQTT session.
*
* Called to resubscribe to the topics that the client has active subscriptions on.
* Internally called when autoreconnect is enabled
* This function restores subscriptions that were previously present in an
* MQTT session. Its primary use is to restore subscriptions after a session
* is manually disconnected and reopened.
*
* @note Call is blocking. The call returns after the receipt of the SUBACK control packet.
* @note This function does not need to be called after @ref mqtt_function_attempt_reconnect
* or if auto-reconnect is enabled.
*
* @param pClient Reference to the IoT Client
* @param[in] pClient MQTT client context
*
* @return An IoT Error Type defining successful/failed subscription
* @return `IoT_Error_t`: See `aws_iot_error.h`
*/
/* @[declare_mqtt_resubscribe] */
IoT_Error_t aws_iot_mqtt_resubscribe(AWS_IoT_Client *pClient);
/* @[declare_mqtt_resubscribe] */
/**
* @brief Unsubscribe to an MQTT topic.
* @brief Unsubscribe from an MQTT topic filter.
*
* Called to send an unsubscribe message to the broker requesting removal of a subscription
* to an MQTT topic.
* @note Call is blocking. The call returns after the receipt of the UNSUBACK control packet.
* This function removes an MQTT subscription previously set by @ref mqtt_function_subscribe.
* It sends an MQTT UNSUBSCRIBE packet to the server and removes the topic's message
* handler stored by the client.
*
* @param pClient Reference to the IoT Client
* @param pTopicName Topic Name to publish to
* @param topicNameLen Length of the topic name
* @param[in] pClient MQTT client context
* @param[in] pTopicFilter Topic filter of the subscription to remove
* @param[in] topicFilterLen Length of topic filter to remove
*
* @return An IoT Error Type defining successful/failed unsubscribe call
* @return `IoT_Error_t`: See `aws_iot_error.h`
*/
/* @[declare_mqtt_unsubscribe] */
IoT_Error_t aws_iot_mqtt_unsubscribe(AWS_IoT_Client *pClient, const char *pTopicFilter, uint16_t topicFilterLen);
/* @[declare_mqtt_unsubscribe] */
/**
* @brief Disconnect an MQTT Connection
* @brief Disconnect an MQTT session.
*
* Called to send a disconnect message to the broker.
* This function sends the MQTT DISCONNECT packet, which closes the MQTT session
* between the client and server. After this function returns, the MQTT client
* context should be either freed with @ref mqtt_function_free or reopened with
* @ref mqtt_function_connect.
*
* @param pClient Reference to the IoT Client
* @param[in] pClient MQTT client context
*
* @return An IoT Error Type defining successful/failed send of the disconnect control packet.
* @return `IoT_Error_t`: See `aws_iot_error.h`
*/
/* @[declare_mqtt_disconnect] */
IoT_Error_t aws_iot_mqtt_disconnect(AWS_IoT_Client *pClient);
/* @[declare_mqtt_disconnect] */
/**
* @brief Yield to the MQTT client
* @brief Provide time for the MQTT client to process events.
*
* Called to yield the current thread to the underlying MQTT client. This time is used by
* the MQTT client to manage PING requests to monitor the health of the TCP connection as
* well as periodically check the socket receive buffer for subscribe messages. Yield()
* must be called at a rate faster than the keepalive interval. It must also be called
* at a rate faster than the incoming message rate as this is the only way the client receives
* processing time to manage incoming messages.
* This function processes the following events:
* - Incoming messages from the server <br>
* Whenever a client publishes a message on a topic, the server sends that
* message to all the clients whose subscriptions match the message's
* topic. The messages sent by the server are received by this function,
* which in turn calls the corresponding message handler. This function
* must be called at a rate faster than the incoming messages, as it is the
* only way the client receives processing time to manage incoming messages.
* - MQTT keep-alive (sending ping requests and processing ping responses) <br>
* The MQTT keep-alive mechanism involves sending pings to the server if the connection
* is idle. Therefore, in the absence of any other messages, <b>this function must be called
* at least once every keep-alive period to send the ping request</b>.
* - @ref mqtt_autoreconnect (if enabled) <br>
* If the client detects a disconnect, the reconnection will be performed in this function.
*
* @param pClient Reference to the IoT Client
* @param timeout_ms Maximum number of milliseconds to pass thread execution to the client.
* @param[in] pClient MQTT client context
* @param[in] timeout_ms Amount of time to yield. This function will return to the caller
* after AT LEAST this amount of thime has passed.
*
* @return An IoT Error Type defining successful/failed client processing.
* If this call results in an error it is likely the MQTT connection has dropped.
* iot_is_mqtt_connected can be called to confirm.
* @return `IoT_Error_t`: See `aws_iot_error.h`
* @return If this call results a negative value, assume the MQTT connection has dropped.
* @ref mqtt_function_is_client_connected can be called to confirm. If a reconnection is
* needed, @ref mqtt_function_attempt_reconnect should be called.
*/
/* @[declare_mqtt_yield] */
IoT_Error_t aws_iot_mqtt_yield(AWS_IoT_Client *pClient, uint32_t timeout_ms);
/* @[declare_mqtt_yield] */
/**
* @brief MQTT Manual Re-Connection Function
* @brief Attempt to reconnect with the MQTT server.
*
* Called to establish an MQTT connection with the AWS IoT Service
* using parameters from the last time a connection was attempted
* Use after disconnect to start the reconnect process manually
* Makes only one reconnect attempt Sets the client state to
* pending reconnect in case of failure
* This function makes a single reconnect attempt with the server. If the
* reconnection is successful, subscriptions from the client's previous
* session are restored as well.
*
* @param pClient Reference to the IoT Client
* If this function fails, the client's state is set to `CLIENT_STATE_PENDING_RECONNECT`.
*
* @return An IoT Error Type defining successful/failed connection
* @param[in] pClient MQTT client context
*
* @return `IoT_Error_t`: See `aws_iot_error.h`
*
* @note Generally, it is not necessary to call this function if @ref mqtt_autoreconnect
* is enabled. This function may still be called to initiate a reconnect attempt when
* auto-reconnect has exhausted all attempts.
*/
/* @[declare_mqtt_attempt_reconnect] */
IoT_Error_t aws_iot_mqtt_attempt_reconnect(AWS_IoT_Client *pClient);
/* @[declare_mqtt_attempt_reconnect] */
#ifdef __cplusplus
}
@@ -26,6 +26,7 @@ extern "C" {
#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include "timer_platform.h"
@@ -69,6 +70,13 @@ void init_timer(Timer *timer) {
timer->end_time = (struct timeval) {0, 0};
}
void delay(unsigned milliseconds)
{
useconds_t sleepTime = (useconds_t)(milliseconds * 1000);
usleep(sleepTime);
}
#ifdef __cplusplus
}
#endif
@@ -34,6 +34,13 @@ struct Timer {
struct timeval end_time;
};
/**
* @brief Delay (sleep) for the specified number of milliseconds.
*
* @param milliseconds The number of milliseconds to sleep.
*/
void delay(unsigned milliseconds);
#ifdef __cplusplus
}
#endif
@@ -19,6 +19,8 @@ extern "C" {
#include <stdbool.h>
#include <string.h>
#include "aws_iot_config.h"
#include <timer_platform.h>
#include <network_interface.h>
@@ -277,6 +279,10 @@ IoT_Error_t iot_tls_connect(Network *pNetwork, TLSConnectParams *params) {
mbedtls_ssl_conf_read_timeout(&(tlsDataParams->conf), IOT_SSL_READ_TIMEOUT);
#ifdef IOT_SSL_SOCKET_NON_BLOCKING
mbedtls_net_set_nonblock(&(tlsDataParams->server_fd));
#endif
return (IoT_Error_t) ret;
}
@@ -32,10 +32,11 @@ IOT_SRC_FILES += $(shell find $(PLATFORM_COMMON_DIR)/ -name '*.c')
#TLS - mbedtls
MBEDTLS_DIR = $(IOT_CLIENT_DIR)/external_libs/mbedTLS
TLS_LIB_DIR = $(MBEDTLS_DIR)/library
CRYPTO_LIB_DIR = $(MBEDTLS_DIR)/library
TLS_INCLUDE_DIR = -I $(MBEDTLS_DIR)/include
EXTERNAL_LIBS += -L$(TLS_LIB_DIR)
LD_FLAG += -Wl,-rpath,$(TLS_LIB_DIR)
LD_FLAG += -ldl $(TLS_LIB_DIR)/libmbedtls.a $(TLS_LIB_DIR)/libmbedcrypto.a $(TLS_LIB_DIR)/libmbedx509.a -lpthread
LD_FLAG += -ldl $(TLS_LIB_DIR)/libmbedtls.a $(CRYPTO_LIB_DIR)/libmbedcrypto.a $(TLS_LIB_DIR)/libmbedx509.a -lpthread
#Aggregate all include and src directories
INCLUDE_ALL_DIRS += $(IOT_INCLUDE_DIRS)
@@ -15,16 +15,16 @@
/**
*
* This example takes the parameters from the aws_iot_config.h file and establishes
* a connection to the AWS IoT MQTT Platform. It performs several operations to
* This example takes the parameters from the aws_iot_config.h file and establishes
* a connection to the AWS IoT MQTT Platform. It performs several operations to
* demonstrate the basic capabilities of the AWS IoT Jobs platform.
*
* If all the certs are correct, you should see the list of pending Job Executions
* printed out by the iot_get_pending_callback_handler. If there are any existing pending
* If all the certs are correct, you should see the list of pending Job Executions
* printed out by the iot_get_pending_callback_handler. If there are any existing pending
* job executions each will be processed one at a time in the iot_next_job_callback_handler.
* After all of the pending jobs have been processed the program will wait for
* notifications for new pending jobs and process them one at a time as they come in.
*
*
* In the main body you can see how each callback is registered for each corresponding
* Jobs topic.
*
@@ -46,23 +46,23 @@
/**
* @brief Default cert location
*/
char certDirectory[PATH_MAX + 1] = "../../../certs";
static char certDirectory[PATH_MAX + 1] = "../../../certs";
/**
* @brief Default MQTT HOST URL is pulled from the aws_iot_config.h
*/
char HostAddress[255] = AWS_IOT_MQTT_HOST;
static char HostAddress[255] = AWS_IOT_MQTT_HOST;
/**
* @brief Default MQTT port is pulled from the aws_iot_config.h
*/
uint32_t port = AWS_IOT_MQTT_PORT;
static uint32_t port = AWS_IOT_MQTT_PORT;
static jsmn_parser jsonParser;
static jsmntok_t jsonTokenStruct[MAX_JSON_TOKEN_EXPECTED];
static int32_t tokenCount;
void iot_get_pending_callback_handler(AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen,
static void iot_get_pending_callback_handler(AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen,
IoT_Publish_Message_Params *params, void *pData) {
IOT_UNUSED(pData);
IOT_UNUSED(pClient);
@@ -91,7 +91,7 @@ void iot_get_pending_callback_handler(AWS_IoT_Client *pClient, char *topicName,
if (jobs) {
IOT_INFO("inProgressJobs: %.*s", jobs->end - jobs->start, (char *)params->payload + jobs->start);
}
}
jobs = findToken("queuedJobs", params->payload, jsonTokenStruct);
@@ -100,7 +100,7 @@ void iot_get_pending_callback_handler(AWS_IoT_Client *pClient, char *topicName,
}
}
void iot_next_job_callback_handler(AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen,
static void iot_next_job_callback_handler(AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen,
IoT_Publish_Message_Params *params, void *pData) {
char topicToPublishUpdate[MAX_JOB_TOPIC_LENGTH_BYTES];
char messageBuffer[200];
@@ -142,7 +142,7 @@ void iot_next_job_callback_handler(AWS_IoT_Client *pClient, char *topicName, uin
char jobId[MAX_SIZE_OF_JOB_ID + 1];
AwsIotJobExecutionUpdateRequest updateRequest;
rc = parseStringValue(jobId, MAX_SIZE_OF_JOB_ID + 1, params->payload, tok);
rc = parseStringValue(jobId, MAX_SIZE_OF_JOB_ID + 1, params->payload, tok);
if(SUCCESS != rc) {
IOT_ERROR("parseStringValue returned error : %d ", rc);
return;
@@ -172,15 +172,19 @@ void iot_next_job_callback_handler(AWS_IoT_Client *pClient, char *topicName, uin
updateRequest.includeJobDocument = false;
updateRequest.clientToken = NULL;
rc = aws_iot_jobs_send_update(pClient, QOS0, AWS_IOT_MY_THING_NAME, jobId, &updateRequest,
rc = aws_iot_jobs_send_update(pClient, QOS0, AWS_IOT_MY_THING_NAME, jobId, &updateRequest,
topicToPublishUpdate, sizeof(topicToPublishUpdate), messageBuffer, sizeof(messageBuffer));
if(SUCCESS != rc) {
IOT_ERROR("aws_iot_jobs_send_update returned error : %d ", rc);
return;
}
}
} else {
IOT_INFO("execution property not found, nothing to do");
IOT_INFO("execution property not found, nothing to do");
}
}
void iot_update_accepted_callback_handler(AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen,
static void iot_update_accepted_callback_handler(AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen,
IoT_Publish_Message_Params *params, void *pData) {
IOT_UNUSED(pData);
IOT_UNUSED(pClient);
@@ -189,7 +193,7 @@ void iot_update_accepted_callback_handler(AWS_IoT_Client *pClient, char *topicNa
IOT_INFO("payload: %.*s", (int) params->payloadLen, (char *)params->payload);
}
void iot_update_rejected_callback_handler(AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen,
static void iot_update_rejected_callback_handler(AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen,
IoT_Publish_Message_Params *params, void *pData) {
IOT_UNUSED(pData);
IOT_UNUSED(pClient);
@@ -200,7 +204,7 @@ void iot_update_rejected_callback_handler(AWS_IoT_Client *pClient, char *topicNa
/* Do error handling here for when the update was rejected */
}
void disconnectCallbackHandler(AWS_IoT_Client *pClient, void *data) {
static void disconnectCallbackHandler(AWS_IoT_Client *pClient, void *data) {
IOT_WARN("MQTT Disconnect");
IoT_Error_t rc = FAILURE;
@@ -230,8 +234,6 @@ int main(int argc, char **argv) {
char CurrentWD[PATH_MAX + 1];
char cPayload[100];
int32_t i = 0;
IoT_Error_t rc = FAILURE;
AWS_IoT_Client client;
@@ -351,6 +353,10 @@ int main(int argc, char **argv) {
paramsQOS0.payloadLen = strlen(cPayload);
rc = aws_iot_jobs_send_query(&client, QOS0, AWS_IOT_MY_THING_NAME, NULL, NULL, topicToPublishGetPending, sizeof(topicToPublishGetPending), NULL, 0, JOB_GET_PENDING_TOPIC);
if(SUCCESS != rc) {
IOT_ERROR("Error calling aws_iot_jobs_send_query: %d ", rc);
return rc;
}
AwsIotDescribeJobExecutionRequest describeRequest;
describeRequest.executionNumber = 0;
@@ -31,10 +31,11 @@ IOT_SRC_FILES += $(shell find $(PLATFORM_COMMON_DIR)/ -name '*.c')
#TLS - mbedtls
MBEDTLS_DIR = $(IOT_CLIENT_DIR)/external_libs/mbedTLS
TLS_LIB_DIR = $(MBEDTLS_DIR)/library
CRYPTO_LIB_DIR = $(MBEDTLS_DIR)/library
TLS_INCLUDE_DIR = -I $(MBEDTLS_DIR)/include
EXTERNAL_LIBS += -L$(TLS_LIB_DIR)
LD_FLAG += -Wl,-rpath,$(TLS_LIB_DIR)
LD_FLAG += -ldl $(TLS_LIB_DIR)/libmbedtls.a $(TLS_LIB_DIR)/libmbedcrypto.a $(TLS_LIB_DIR)/libmbedx509.a
LD_FLAG += -ldl $(TLS_LIB_DIR)/libmbedtls.a $(CRYPTO_LIB_DIR)/libmbedcrypto.a $(TLS_LIB_DIR)/libmbedx509.a
#Aggregate all include and src directories
@@ -51,7 +52,7 @@ LOG_FLAGS += -DENABLE_IOT_INFO
LOG_FLAGS += -DENABLE_IOT_WARN
LOG_FLAGS += -DENABLE_IOT_ERROR
COMPILER_FLAGS += -g
COMPILER_FLAGS += -g
COMPILER_FLAGS += $(LOG_FLAGS)
#If the processor is big endian uncomment the compiler flag
#COMPILER_FLAGS += -DREVERSED
@@ -77,7 +77,7 @@ static void simulateRoomTemperature(float *pRoomTemperature) {
*pRoomTemperature += deltaChange;
}
void ShadowUpdateStatusCallback(const char *pThingName, ShadowActions_t action, Shadow_Ack_Status_t status,
static void ShadowUpdateStatusCallback(const char *pThingName, ShadowActions_t action, Shadow_Ack_Status_t status,
const char *pReceivedJsonDocument, void *pContextData) {
IOT_UNUSED(pThingName);
IOT_UNUSED(action);
@@ -93,7 +93,7 @@ void ShadowUpdateStatusCallback(const char *pThingName, ShadowActions_t action,
}
}
void windowActuate_Callback(const char *pJsonString, uint32_t JsonStringDataLen, jsonStruct_t *pContext) {
static void windowActuate_Callback(const char *pJsonString, uint32_t JsonStringDataLen, jsonStruct_t *pContext) {
IOT_UNUSED(pJsonString);
IOT_UNUSED(JsonStringDataLen);
@@ -102,7 +102,7 @@ void windowActuate_Callback(const char *pJsonString, uint32_t JsonStringDataLen,
}
}
void parseInputArgsForConnectParams(int argc, char **argv) {
static void parseInputArgsForConnectParams(int argc, char **argv) {
int opt;
while(-1 != (opt = getopt(argc, argv, "h:p:c:n:"))) {
@@ -113,7 +113,7 @@ void parseInputArgsForConnectParams(int argc, char **argv) {
break;
case 'p':
port = atoi(optarg);
IOT_DEBUG("arg %s", optarg);
IOT_DEBUG("port %s", optarg);
break;
case 'c':
strncpy(certDirectory, optarg, PATH_MAX + 1);
@@ -142,11 +142,9 @@ void parseInputArgsForConnectParams(int argc, char **argv) {
int main(int argc, char **argv) {
IoT_Error_t rc = FAILURE;
int32_t i = 0;
char JsonDocumentBuffer[MAX_LENGTH_OF_UPDATE_JSON_BUFFER];
size_t sizeOfJsonDocumentBuffer = sizeof(JsonDocumentBuffer) / sizeof(JsonDocumentBuffer[0]);
char *pJsonStringToUpdate;
float temperature = 0.0;
bool windowOpen = false;
@@ -171,23 +169,24 @@ int main(int argc, char **argv) {
IOT_INFO("\nAWS IoT SDK Version %d.%d.%d-%s\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_TAG);
getcwd(CurrentWD, sizeof(CurrentWD));
snprintf(rootCA, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_ROOT_CA_FILENAME);
snprintf(clientCRT, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_CERTIFICATE_FILENAME);
snprintf(clientKey, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_PRIVATE_KEY_FILENAME);
IOT_DEBUG("rootCA %s", rootCA);
IOT_DEBUG("clientCRT %s", clientCRT);
IOT_DEBUG("clientKey %s", clientKey);
parseInputArgsForConnectParams(argc, argv);
// generate the paths of the credentials
getcwd(CurrentWD, sizeof(CurrentWD));
snprintf(rootCA, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_ROOT_CA_FILENAME);
snprintf(clientCRT, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_CERTIFICATE_FILENAME);
snprintf(clientKey, PATH_MAX + 1, "%s/%s/%s", CurrentWD, certDirectory, AWS_IOT_PRIVATE_KEY_FILENAME);
// initialize the mqtt client
AWS_IoT_Client mqttClient;
ShadowInitParameters_t sp = ShadowInitParametersDefault;
sp.pHost = AWS_IOT_MQTT_HOST;
sp.port = AWS_IOT_MQTT_PORT;
sp.pHost = HostAddress;
sp.port = port;
sp.pClientCRT = clientCRT;
sp.pClientKey = clientKey;
sp.pRootCA = rootCA;
@@ -31,18 +31,19 @@ IOT_SRC_FILES += $(shell find $(PLATFORM_COMMON_DIR)/ -name '*.c')
#TLS - mbedtls
MBEDTLS_DIR = $(IOT_CLIENT_DIR)/external_libs/mbedTLS
TLS_LIB_DIR = $(MBEDTLS_DIR)/library
CRYPTO_LIB_DIR = $(MBEDTLS_DIR)/library
TLS_INCLUDE_DIR = -I $(MBEDTLS_DIR)/include
EXTERNAL_LIBS += -L$(TLS_LIB_DIR)
LD_FLAG += -Wl,-rpath,$(TLS_LIB_DIR)
LD_FLAG += -ldl $(TLS_LIB_DIR)/libmbedtls.a $(TLS_LIB_DIR)/libmbedcrypto.a $(TLS_LIB_DIR)/libmbedx509.a
LD_FLAG += -ldl $(TLS_LIB_DIR)/libmbedtls.a $(CRYPTO_LIB_DIR)/libmbedcrypto.a $(TLS_LIB_DIR)/libmbedx509.a
#Aggregate all include and src directories
INCLUDE_ALL_DIRS += $(IOT_INCLUDE_DIRS)
INCLUDE_ALL_DIRS += $(MQTT_INCLUDE_DIR)
INCLUDE_ALL_DIRS += $(IOT_INCLUDE_DIRS)
INCLUDE_ALL_DIRS += $(MQTT_INCLUDE_DIR)
INCLUDE_ALL_DIRS += $(TLS_INCLUDE_DIR)
INCLUDE_ALL_DIRS += $(APP_INCLUDE_DIRS)
SRC_FILES += $(MQTT_SRC_FILES)
SRC_FILES += $(APP_SRC_FILES)
SRC_FILES += $(IOT_SRC_FILES)
@@ -53,7 +54,7 @@ LOG_FLAGS += -DENABLE_IOT_INFO
LOG_FLAGS += -DENABLE_IOT_WARN
LOG_FLAGS += -DENABLE_IOT_ERROR
COMPILER_FLAGS += -g
COMPILER_FLAGS += -g
COMPILER_FLAGS += $(LOG_FLAGS)
#If the processor is big endian uncomment the compiler flag
@@ -53,30 +53,113 @@
* @note Ensure the buffer sizes in aws_iot_config.h are big enough to receive the delta message. The delta message will also contain the metadata with the timestamps
*/
char certDirectory[PATH_MAX + 1] = "../../../certs";
static char certDirectory[PATH_MAX + 1] = "../../../certs";
#define HOST_ADDRESS_SIZE 255
char HostAddress[HOST_ADDRESS_SIZE] = AWS_IOT_MQTT_HOST;
uint32_t port = AWS_IOT_MQTT_PORT;
bool messageArrivedOnDelta = false;
static char HostAddress[HOST_ADDRESS_SIZE] = AWS_IOT_MQTT_HOST;
static uint32_t port = AWS_IOT_MQTT_PORT;
static bool messageArrivedOnDelta = false;
/*
* @note The delta message is always sent on the "state" key in the json
* @note Any time messages are bigger than AWS_IOT_MQTT_RX_BUF_LEN the underlying MQTT library will ignore it. The maximum size of the message that can be received is limited to the AWS_IOT_MQTT_RX_BUF_LEN
*/
char stringToEchoDelta[SHADOW_MAX_SIZE_OF_RX_BUFFER];
static char stringToEchoDelta[SHADOW_MAX_SIZE_OF_RX_BUFFER];
/**
* @brief This function builds a full Shadow expected JSON document by putting the data in the reported section
*
* @param pJsonDocument Buffer to be filled up with the JSON data
* @param maxSizeOfJsonDocument maximum size of the buffer that could be used to fill
* @param pReceivedDeltaData This is the data that will be embedded in the reported section of the JSON document
* @param lengthDelta Length of the data
*/
static bool buildJSONForReported(char *pJsonDocument, size_t maxSizeOfJsonDocument, const char *pReceivedDeltaData, uint32_t lengthDelta) {
int32_t ret;
if (NULL == pJsonDocument) {
return false;
}
char tempClientTokenBuffer[MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE];
if(aws_iot_fill_with_client_token(tempClientTokenBuffer, MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE) != SUCCESS){
return false;
}
ret = snprintf(pJsonDocument, maxSizeOfJsonDocument, "{\"state\":{\"reported\":%.*s}, \"clientToken\":\"%s\"}", lengthDelta, pReceivedDeltaData, tempClientTokenBuffer);
if (ret >= maxSizeOfJsonDocument || ret < 0) {
return false;
}
return true;
}
// Helper functions
void parseInputArgsForConnectParams(int argc, char** argv);
static void parseInputArgsForConnectParams(int argc, char** argv) {
int opt;
while (-1 != (opt = getopt(argc, argv, "h:p:c:"))) {
switch (opt) {
case 'h':
strncpy(HostAddress, optarg, HOST_ADDRESS_SIZE);
IOT_DEBUG("Host %s", optarg);
break;
case 'p':
port = atoi(optarg);
IOT_DEBUG("arg %s", optarg);
break;
case 'c':
strncpy(certDirectory, optarg, PATH_MAX + 1);
IOT_DEBUG("cert root directory %s", optarg);
break;
case '?':
if (optopt == 'c') {
IOT_ERROR("Option -%c requires an argument.", optopt);
} else if (isprint(optopt)) {
IOT_WARN("Unknown option `-%c'.", optopt);
} else {
IOT_WARN("Unknown option character `\\x%x'.", optopt);
}
break;
default:
IOT_ERROR("ERROR in command line argument parsing");
break;
}
}
}
// Shadow Callback for receiving the delta
void DeltaCallback(const char *pJsonValueBuffer, uint32_t valueLength, jsonStruct_t *pJsonStruct_t);
static void DeltaCallback(const char *pJsonValueBuffer, uint32_t valueLength, jsonStruct_t *pJsonStruct_t) {
IOT_UNUSED(pJsonStruct_t);
void UpdateStatusCallback(const char *pThingName, ShadowActions_t action, Shadow_Ack_Status_t status,
const char *pReceivedJsonDocument, void *pContextData);
IOT_DEBUG("Received Delta message %.*s", valueLength, pJsonValueBuffer);
if (buildJSONForReported(stringToEchoDelta, SHADOW_MAX_SIZE_OF_RX_BUFFER, pJsonValueBuffer, valueLength)) {
messageArrivedOnDelta = true;
}
}
static void UpdateStatusCallback(const char *pThingName, ShadowActions_t action, Shadow_Ack_Status_t status,
const char *pReceivedJsonDocument, void *pContextData) {
IOT_UNUSED(pThingName);
IOT_UNUSED(action);
IOT_UNUSED(pReceivedJsonDocument);
IOT_UNUSED(pContextData);
if(SHADOW_ACK_TIMEOUT == status) {
IOT_INFO("Update Timeout--");
} else if(SHADOW_ACK_REJECTED == status) {
IOT_INFO("Update RejectedXX");
} else if(SHADOW_ACK_ACCEPTED == status) {
IOT_INFO("Update Accepted !!");
}
}
int main(int argc, char** argv) {
IoT_Error_t rc = SUCCESS;
int32_t i = 0;
char rootCA[PATH_MAX + 1];
char clientCRT[PATH_MAX + 1];
@@ -186,93 +269,3 @@ int main(int argc, char** argv) {
return rc;
}
/**
* @brief This function builds a full Shadow expected JSON document by putting the data in the reported section
*
* @param pJsonDocument Buffer to be filled up with the JSON data
* @param maxSizeOfJsonDocument maximum size of the buffer that could be used to fill
* @param pReceivedDeltaData This is the data that will be embedded in the reported section of the JSON document
* @param lengthDelta Length of the data
*/
bool buildJSONForReported(char *pJsonDocument, size_t maxSizeOfJsonDocument, const char *pReceivedDeltaData, uint32_t lengthDelta) {
int32_t ret;
if (NULL == pJsonDocument) {
return false;
}
char tempClientTokenBuffer[MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE];
if(aws_iot_fill_with_client_token(tempClientTokenBuffer, MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE) != SUCCESS){
return false;
}
ret = snprintf(pJsonDocument, maxSizeOfJsonDocument, "{\"state\":{\"reported\":%.*s}, \"clientToken\":\"%s\"}", lengthDelta, pReceivedDeltaData, tempClientTokenBuffer);
if (ret >= maxSizeOfJsonDocument || ret < 0) {
return false;
}
return true;
}
void parseInputArgsForConnectParams(int argc, char** argv) {
int opt;
while (-1 != (opt = getopt(argc, argv, "h:p:c:"))) {
switch (opt) {
case 'h':
strncpy(HostAddress, optarg, HOST_ADDRESS_SIZE);
IOT_DEBUG("Host %s", optarg);
break;
case 'p':
port = atoi(optarg);
IOT_DEBUG("arg %s", optarg);
break;
case 'c':
strncpy(certDirectory, optarg, PATH_MAX + 1);
IOT_DEBUG("cert root directory %s", optarg);
break;
case '?':
if (optopt == 'c') {
IOT_ERROR("Option -%c requires an argument.", optopt);
} else if (isprint(optopt)) {
IOT_WARN("Unknown option `-%c'.", optopt);
} else {
IOT_WARN("Unknown option character `\\x%x'.", optopt);
}
break;
default:
IOT_ERROR("ERROR in command line argument parsing");
break;
}
}
}
void DeltaCallback(const char *pJsonValueBuffer, uint32_t valueLength, jsonStruct_t *pJsonStruct_t) {
IOT_UNUSED(pJsonStruct_t);
IOT_DEBUG("Received Delta message %.*s", valueLength, pJsonValueBuffer);
if (buildJSONForReported(stringToEchoDelta, SHADOW_MAX_SIZE_OF_RX_BUFFER, pJsonValueBuffer, valueLength)) {
messageArrivedOnDelta = true;
}
}
void UpdateStatusCallback(const char *pThingName, ShadowActions_t action, Shadow_Ack_Status_t status,
const char *pReceivedJsonDocument, void *pContextData) {
IOT_UNUSED(pThingName);
IOT_UNUSED(action);
IOT_UNUSED(pReceivedJsonDocument);
IOT_UNUSED(pContextData);
if(SHADOW_ACK_TIMEOUT == status) {
IOT_INFO("Update Timeout--");
} else if(SHADOW_ACK_REJECTED == status) {
IOT_INFO("Update RejectedXX");
} else if(SHADOW_ACK_ACCEPTED == status) {
IOT_INFO("Update Accepted !!");
}
}
@@ -31,10 +31,11 @@ IOT_SRC_FILES += $(shell find $(PLATFORM_COMMON_DIR)/ -name '*.c')
#TLS - mbedtls
MBEDTLS_DIR = $(IOT_CLIENT_DIR)/external_libs/mbedTLS
TLS_LIB_DIR = $(MBEDTLS_DIR)/library
CRYPTO_LIB_DIR = $(MBEDTLS_DIR)/library
TLS_INCLUDE_DIR = -I $(MBEDTLS_DIR)/include
EXTERNAL_LIBS += -L$(TLS_LIB_DIR)
LD_FLAG += -Wl,-rpath,$(TLS_LIB_DIR)
LD_FLAG += -ldl $(TLS_LIB_DIR)/libmbedtls.a $(TLS_LIB_DIR)/libmbedcrypto.a $(TLS_LIB_DIR)/libmbedx509.a -lpthread
LD_FLAG += -ldl $(TLS_LIB_DIR)/libmbedtls.a $(CRYPTO_LIB_DIR)/libmbedcrypto.a $(TLS_LIB_DIR)/libmbedx509.a -lpthread
#Aggregate all include and src directories
INCLUDE_ALL_DIRS += $(IOT_INCLUDE_DIRS)
@@ -42,24 +42,24 @@
/**
* @brief Default cert location
*/
char certDirectory[PATH_MAX + 1] = "../../../certs";
static char certDirectory[PATH_MAX + 1] = "../../../certs";
/**
* @brief Default MQTT HOST URL is pulled from the aws_iot_config.h
*/
char HostAddress[HOST_ADDRESS_SIZE] = AWS_IOT_MQTT_HOST;
static char HostAddress[HOST_ADDRESS_SIZE] = AWS_IOT_MQTT_HOST;
/**
* @brief Default MQTT port is pulled from the aws_iot_config.h
*/
uint32_t port = AWS_IOT_MQTT_PORT;
static uint32_t port = AWS_IOT_MQTT_PORT;
/**
* @brief This parameter will avoid infinite loop of publish and exit the program after certain number of publishes
*/
uint32_t publishCount = 0;
void iot_subscribe_callback_handler(AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen,
static void iot_subscribe_callback_handler(AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen,
IoT_Publish_Message_Params *params, void *pData) {
IOT_UNUSED(pData);
IOT_UNUSED(pClient);
@@ -67,7 +67,7 @@ void iot_subscribe_callback_handler(AWS_IoT_Client *pClient, char *topicName, ui
IOT_INFO("%.*s\t%.*s", topicNameLen, topicName, (int) params->payloadLen, (char *) params->payload);
}
void disconnectCallbackHandler(AWS_IoT_Client *pClient, void *data) {
static void disconnectCallbackHandler(AWS_IoT_Client *pClient, void *data) {
IOT_WARN("MQTT Disconnect");
IoT_Error_t rc = FAILURE;
@@ -90,7 +90,7 @@ void disconnectCallbackHandler(AWS_IoT_Client *pClient, void *data) {
}
}
void parseInputArgsForConnectParams(int argc, char **argv) {
static void parseInputArgsForConnectParams(int argc, char **argv) {
int opt;
while(-1 != (opt = getopt(argc, argv, "h:p:c:x:"))) {
@@ -31,10 +31,11 @@ IOT_SRC_FILES += $(shell find $(PLATFORM_COMMON_DIR)/ -name '*.c')
#TLS - mbedtls
MBEDTLS_DIR = $(IOT_CLIENT_DIR)/external_libs/mbedTLS
TLS_LIB_DIR = $(MBEDTLS_DIR)/library
CRYPTO_LIB_DIR = $(MBEDTLS_DIR)/library
TLS_INCLUDE_DIR = -I $(MBEDTLS_DIR)/include
EXTERNAL_LIBS += -L$(TLS_LIB_DIR)
LD_FLAG += -Wl,-rpath,$(TLS_LIB_DIR)
LD_FLAG += -ldl $(TLS_LIB_DIR)/libmbedtls.a $(TLS_LIB_DIR)/libmbedcrypto.a $(TLS_LIB_DIR)/libmbedx509.a -lpthread
LD_FLAG += -ldl $(TLS_LIB_DIR)/libmbedtls.a $(CRYPTO_LIB_DIR)/libmbedcrypto.a $(TLS_LIB_DIR)/libmbedx509.a -lpthread
#Aggregate all include and src directories
INCLUDE_ALL_DIRS += $(IOT_INCLUDE_DIRS)
@@ -41,24 +41,24 @@
/**
* @brief Default cert location
*/
char certDirectory[PATH_MAX + 1] = "../../../certs";
static char certDirectory[PATH_MAX + 1] = "../../../certs";
/**
* @brief Default MQTT HOST URL is pulled from the aws_iot_config.h
*/
char HostAddress[HOST_ADDRESS_SIZE] = AWS_IOT_MQTT_HOST;
static char HostAddress[HOST_ADDRESS_SIZE] = AWS_IOT_MQTT_HOST;
/**
* @brief Default MQTT port is pulled from the aws_iot_config.h
*/
uint32_t port = AWS_IOT_MQTT_PORT;
static uint32_t port = AWS_IOT_MQTT_PORT;
/**
* @brief This parameter will avoid infinite loop of publish and exit the program after certain number of publishes
*/
uint32_t publishCount = 0;
static uint32_t publishCount = 0;
void iot_subscribe_callback_handler(AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen,
static void iot_subscribe_callback_handler(AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen,
IoT_Publish_Message_Params *params, void *pData) {
IOT_UNUSED(pData);
IOT_UNUSED(pClient);
@@ -66,7 +66,7 @@ void iot_subscribe_callback_handler(AWS_IoT_Client *pClient, char *topicName, ui
IOT_INFO("%.*s\t%.*s", topicNameLen, topicName, (int) params->payloadLen, (char *) params->payload);
}
void disconnectCallbackHandler(AWS_IoT_Client *pClient, void *data) {
static void disconnectCallbackHandler(AWS_IoT_Client *pClient, void *data) {
IOT_WARN("MQTT Disconnect");
IoT_Error_t rc = FAILURE;
@@ -89,7 +89,7 @@ void disconnectCallbackHandler(AWS_IoT_Client *pClient, void *data) {
}
}
void parseInputArgsForConnectParams(int argc, char **argv) {
static void parseInputArgsForConnectParams(int argc, char **argv) {
int opt;
while(-1 != (opt = getopt(argc, argv, "h:p:c:x:"))) {
@@ -43,11 +43,15 @@ extern "C" {
#include "aws_iot_log.h"
#include "aws_iot_mqtt_client_interface.h"
#include "aws_iot_mqtt_client_common_internal.h"
#include "aws_iot_version.h"
#if !DISABLE_METRICS
/** Length of metrics username */
#define SDK_METRICS_LEN 25
/** Metrics username for AWS IoT */
#define SDK_METRICS_TEMPLATE "?SDK=C&Version=%d.%d.%d"
/** Buffer for metrics username */
static char pUsernameTemp[SDK_METRICS_LEN] = {0};
#endif
@@ -69,6 +73,14 @@ ClientState aws_iot_mqtt_get_client_state(AWS_IoT_Client *pClient) {
}
#ifdef _ENABLE_THREAD_SUPPORT_
/**
* @brief Lock a mutex in the MQTT client
*
* @param pClient MQTT client
* @param pMutex Mutex to lock
*
* @return IoT_Error_t of mutex operation
*/
IoT_Error_t aws_iot_mqtt_client_lock_mutex(AWS_IoT_Client *pClient, IoT_Mutex_t *pMutex) {
FUNC_ENTRY;
IoT_Error_t threadRc = FAILURE;
@@ -91,6 +103,14 @@ IoT_Error_t aws_iot_mqtt_client_lock_mutex(AWS_IoT_Client *pClient, IoT_Mutex_t
FUNC_EXIT_RC(SUCCESS);
}
/**
* @brief Unlock a mutex in the MQTT client
*
* @param pClient MQTT client
* @param pMutex Mutex to unlock
*
* @return IoT_Error_t of mutex operation
*/
IoT_Error_t aws_iot_mqtt_client_unlock_mutex(AWS_IoT_Client *pClient, IoT_Mutex_t *pMutex) {
if(NULL == pClient || NULL == pMutex) {
return NULL_VALUE_ERROR;
@@ -100,6 +120,15 @@ IoT_Error_t aws_iot_mqtt_client_unlock_mutex(AWS_IoT_Client *pClient, IoT_Mutex_
}
#endif
/**
* @brief Change the state in an MQTT client
*
* @param pClient MQTT client
* @param expectedCurrentState What the current state of the client should be
* @param newState What the new state of the client should be
*
* @return IoT_Error_t of state change
*/
IoT_Error_t aws_iot_mqtt_set_client_state(AWS_IoT_Client *pClient, ClientState expectedCurrentState,
ClientState newState) {
IoT_Error_t rc;
@@ -273,7 +302,8 @@ IoT_Error_t aws_iot_mqtt_init(AWS_IoT_Client *pClient, const IoT_Client_Init_Par
FUNC_EXIT_RC(rc);
}
init_timer(&(pClient->pingTimer));
init_timer(&(pClient->pingReqTimer));
init_timer(&(pClient->pingRespTimer));
init_timer(&(pClient->reconnectDelayTimer));
pClient->clientStatus.clientState = CLIENT_STATE_INITIALIZED;
@@ -365,4 +395,3 @@ void aws_iot_mqtt_reset_network_disconnected_count(AWS_IoT_Client *pClient) {
#ifdef __cplusplus
}
#endif
@@ -43,13 +43,15 @@ extern "C" {
#include <aws_iot_mqtt_client.h>
#include "aws_iot_mqtt_client_common_internal.h"
/* Max length of packet header */
/** Max length of packet header */
#define MAX_NO_OF_REMAINING_LENGTH_BYTES 4
/**
* Encodes the message length according to the MQTT algorithm
* @brief Encodes the message length according to the MQTT algorithm
*
* @param buf the buffer into which the encoded data is written
* @param length the length to be encoded
*
* @return the number of bytes written to buffer
*/
size_t aws_iot_mqtt_internal_write_len_to_buffer(unsigned char *buf, uint32_t length) {
@@ -71,10 +73,13 @@ size_t aws_iot_mqtt_internal_write_len_to_buffer(unsigned char *buf, uint32_t le
}
/**
* Decodes the message length according to the MQTT algorithm
* @param the buffer containing the message
* @param value the decoded length returned
* @return the number of bytes read from the socket
* @brief Decodes the message length according to the MQTT algorithm
*
* @param buf the buffer containing the message
* @param decodedLen value the decoded length returned
* @param readBytesLen output parameter for the number of bytes read from the socket
*
* @return IoT_Error_t indicating decode status
*/
IoT_Error_t aws_iot_mqtt_internal_decode_remaining_length_from_buffer(unsigned char *buf, uint32_t *decodedLen,
uint32_t *readBytesLen) {
@@ -102,6 +107,13 @@ IoT_Error_t aws_iot_mqtt_internal_decode_remaining_length_from_buffer(unsigned c
FUNC_EXIT_RC(SUCCESS);
}
/**
* @brief Calculates the length of the "remaining length" encoding
*
* @param rem_len "remaining length" to encode
*
* @return length of the remaining length encoding
*/
uint32_t aws_iot_mqtt_internal_get_final_packet_length_from_remaining_length(uint32_t rem_len) {
rem_len += 1; /* header byte */
/* now remaining_length field (MQTT 3.1.1 - 2.2.3)*/
@@ -118,7 +130,8 @@ uint32_t aws_iot_mqtt_internal_get_final_packet_length_from_remaining_length(uin
}
/**
* Calculates uint16 packet id from two bytes read from the input buffer
* @brief Calculates uint16 packet id from two bytes read from the input buffer
*
* Checks Endianness at runtime
*
* @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
@@ -136,7 +149,8 @@ uint16_t aws_iot_mqtt_internal_read_uint16_t(unsigned char **pptr) {
}
/**
* Writes an integer as 2 bytes to an output buffer.
* @brief Writes an integer as 2 bytes to an output buffer.
*
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
* @param anInt the integer to write
*/
@@ -148,7 +162,8 @@ void aws_iot_mqtt_internal_write_uint_16(unsigned char **pptr, uint16_t anInt) {
}
/**
* Reads one character from the input buffer.
* @brief Reads one character from the input buffer.
*
* @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
* @return the character read
*/
@@ -159,7 +174,8 @@ unsigned char aws_iot_mqtt_internal_read_char(unsigned char **pptr) {
}
/**
* Writes one character to an output buffer.
* @brief Writes one character to an output buffer.
*
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
* @param c the character to write
*/
@@ -168,6 +184,13 @@ void aws_iot_mqtt_internal_write_char(unsigned char **pptr, unsigned char c) {
(*pptr)++;
}
/**
* @brief Writes a UTF-8 string into an MQTT packet
*
* @param pptr Where the string should be written
* @param string The string to write
* @param stringLen Length to write
*/
void aws_iot_mqtt_internal_write_utf8_string(unsigned char **pptr, const char *string, uint16_t stringLen) {
/* Nothing that calls this function will have a stringLen with a size larger than 2 bytes (MQTT 3.1.1 - 1.5.3) */
aws_iot_mqtt_internal_write_uint_16(pptr, stringLen);
@@ -178,10 +201,19 @@ void aws_iot_mqtt_internal_write_utf8_string(unsigned char **pptr, const char *s
}
/**
* Initialize the MQTTHeader structure. Used to ensure that Header bits are
* always initialized using the proper mappings. No Endianness issues here since
* the individual fields are all less than a byte. Also generates no warnings since
* all fields are initialized using hex constants
* @brief Initialize the MQTTHeader structure.
*
* Used to ensure that Header bits are always initialized using the proper mappings.
* No Endianness issues here since the individual fields are all less than a byte.
* Also generates no warnings since all fields are initialized using hex constants.
*
* @param pHeader Header to initialize
* @param message_type MQTT packet type
* @param qos Quality of service for packet
* @param dup DUP flag of a publish
* @param retained RETAIN flag of a publish
*
* @return Returns SUCCESS unless an invalid packet type is given.
*/
IoT_Error_t aws_iot_mqtt_internal_init_header(MQTTHeader *pHeader, MessageTypes message_type,
QoS qos, uint8_t dup, uint8_t retained) {
@@ -264,10 +296,19 @@ IoT_Error_t aws_iot_mqtt_internal_init_header(MQTTHeader *pHeader, MessageTypes
FUNC_EXIT_RC(SUCCESS);
}
/**
* @brief Send an MQTT packet on the network
*
* @param pClient MQTT client which holds packet
* @param length Length of packet to send
* @param pTimer Amount of time allowed to send packet
*
* @return IoT_Error_t of send status
*/
IoT_Error_t aws_iot_mqtt_internal_send_packet(AWS_IoT_Client *pClient, size_t length, Timer *pTimer) {
size_t sentLen, sent;
IoT_Error_t rc;
IoT_Error_t rc = FAILURE;
FUNC_ENTRY;
@@ -344,7 +385,7 @@ static IoT_Error_t _aws_iot_mqtt_internal_readWrapper( AWS_IoT_Client *pClient,
rc = SUCCESS;
}
return rc;
}
@@ -404,8 +445,8 @@ static IoT_Error_t _aws_iot_mqtt_internal_read_packet(AWS_IoT_Client *pClient, T
rc = _aws_iot_mqtt_internal_decode_packet_remaining_len(pClient, &offset, &rem_len, pTimer);
if(SUCCESS != rc) {
return rc;
}
}
/* if the buffer is too short then the message will be dropped silently */
if((rem_len + offset) >= pClient->clientData.readBufSize) {
bytes_to_be_read = pClient->clientData.readBufSize;
@@ -529,12 +570,13 @@ static IoT_Error_t _aws_iot_mqtt_internal_deliver_message(AWS_IoT_Client *pClien
FUNC_EXIT_RC(rc);
}
static IoT_Error_t _aws_iot_mqtt_internal_handle_publish(AWS_IoT_Client *pClient, Timer *pTimer) {
static IoT_Error_t _aws_iot_mqtt_internal_handle_publish(AWS_IoT_Client *pClient) {
char *topicName;
uint16_t topicNameLen;
uint32_t len;
IoT_Error_t rc;
IoT_Publish_Message_Params msg;
Timer sendTimer;
FUNC_ENTRY;
@@ -552,32 +594,45 @@ static IoT_Error_t _aws_iot_mqtt_internal_handle_publish(AWS_IoT_Client *pClient
FUNC_EXIT_RC(rc);
}
/* Send acknowledgement of QoS 1 message. */
if(QOS1 == msg.qos) {
/* Initialize timer for sending PUBACK. */
init_timer(&sendTimer);
countdown_ms(&sendTimer, pClient->clientData.commandTimeoutMs);
/* Generate and send a PUBACK. Warn if the PUBACK isn't sent; the server
will send the PUBLISH again in that case. */
rc = aws_iot_mqtt_internal_serialize_ack(pClient->clientData.writeBuf,
pClient->clientData.writeBufSize, PUBACK, 0, msg.id, &len);
if(SUCCESS == rc) {
rc = aws_iot_mqtt_internal_send_packet(pClient, len, &sendTimer);
if(SUCCESS != rc) {
IOT_WARN("Failed to send PUBACK");
}
} else {
IOT_WARN("Failed to generate PUBACK");
}
}
rc = _aws_iot_mqtt_internal_deliver_message(pClient, topicName, topicNameLen, &msg);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
if(QOS0 == msg.qos) {
/* No further processing required for QoS0 */
FUNC_EXIT_RC(SUCCESS);
}
/* Message assumed to be QoS1 since we do not support QoS2 at this time */
rc = aws_iot_mqtt_internal_serialize_ack(pClient->clientData.writeBuf, pClient->clientData.writeBufSize,
PUBACK, 0, msg.id, &len);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
rc = aws_iot_mqtt_internal_send_packet(pClient, len, pTimer);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
FUNC_EXIT_RC(SUCCESS);
}
/**
* @brief Read an MQTT packet from the network
*
* @param pClient MQTT client
* @param pTimer Amount of time allowed to read packet
* @param pPacketType Output parameter for packet read from network
*
* @return IoT_Error_t of read status
*/
IoT_Error_t aws_iot_mqtt_internal_cycle_read(AWS_IoT_Client *pClient, Timer *pTimer, uint8_t *pPacketType) {
IoT_Error_t rc;
@@ -621,7 +676,7 @@ IoT_Error_t aws_iot_mqtt_internal_cycle_read(AWS_IoT_Client *pClient, Timer *pTi
/* SDK is blocking, these responses will be forwarded to calling function to process */
break;
case PUBLISH: {
rc = _aws_iot_mqtt_internal_handle_publish(pClient, pTimer);
rc = _aws_iot_mqtt_internal_handle_publish(pClient);
break;
}
case PUBREC:
@@ -629,8 +684,8 @@ IoT_Error_t aws_iot_mqtt_internal_cycle_read(AWS_IoT_Client *pClient, Timer *pTi
/* QoS2 not supported at this time */
break;
case PINGRESP: {
pClient->clientStatus.isPingOutstanding = 0;
countdown_sec(&pClient->pingTimer, pClient->clientData.keepAliveInterval);
/* There is no outstanding ping request anymore. */
pClient->clientStatus.isPingOutstanding = false;
break;
}
default: {
@@ -644,12 +699,29 @@ IoT_Error_t aws_iot_mqtt_internal_cycle_read(AWS_IoT_Client *pClient, Timer *pTi
return rc;
}
/**
* @brief Flush incoming data from the MQTT client
*
* @param pClient Client with data to flush
*
* @return Always returns SUCCESS
*/
IoT_Error_t aws_iot_mqtt_internal_flushBuffers( AWS_IoT_Client *pClient ) {
pClient->clientData.readBufIndex = 0;
return SUCCESS;
}
/* only used in single-threaded mode where one command at a time is in process */
/**
* @brief Wait until a packet is read from the network
*
* Only used in single-threaded mode where one command at a time is in process
*
* @param pClient MQTT client
* @param packetType MQTT packet to read
* @param pTimer Amount of time allowed to read packet
*
* @return IoT_Error_t of read status
*/
IoT_Error_t aws_iot_mqtt_internal_wait_for_read(AWS_IoT_Client *pClient, uint8_t packetType, Timer *pTimer) {
IoT_Error_t rc;
uint8_t read_packet_type;
@@ -676,10 +748,10 @@ IoT_Error_t aws_iot_mqtt_internal_wait_for_read(AWS_IoT_Client *pClient, uint8_t
/**
* Serializes a 0-length packet into the supplied buffer, ready for writing to a socket
* @param buf the buffer into which the packet will be serialized
* @param buflen the length in bytes of the supplied buffer, to avoid overruns
* @param packettype the message type
* @param serialized length
* @param pTxBuf the buffer into which the packet will be serialized
* @param txBufLen the length in bytes of the supplied buffer, to avoid overruns
* @param packetType the message type
* @param pSerializedLength length
* @return IoT_Error_t indicating function execution status
*/
IoT_Error_t aws_iot_mqtt_internal_serialize_zero(unsigned char *pTxBuf, size_t txBufLen, MessageTypes packetType,
@@ -45,6 +45,7 @@ extern "C" {
#include "aws_iot_mqtt_client_interface.h"
#include "aws_iot_mqtt_client_common_internal.h"
/** connect flags byte */
typedef union {
uint8_t all; /**< all connect flags */
#if defined(REVERSED)
@@ -57,27 +58,21 @@ typedef union {
unsigned int will : 1; /**< will flag */
unsigned int cleansession : 1; /**< clean session flag */
unsigned int : 1; /**< unused */
} bits;
} bits; /**< connect flags byte (reversed order) */
#else
struct {
unsigned int : 1;
/**< unused */
unsigned int cleansession : 1;
/**< cleansession flag */
unsigned int will : 1;
/**< will flag */
unsigned int willQoS : 2;
/**< will QoS value */
unsigned int willRetain : 1;
/**< will retain setting */
unsigned int password : 1;
/**< 3.1 password */
unsigned int username : 1; /**< 3.1 user name */
} bits;
unsigned int : 1; /**< unused */
unsigned int cleansession : 1; /**< cleansession flag */
unsigned int will : 1; /**< will flag */
unsigned int willQoS : 2; /**< will QoS value */
unsigned int willRetain : 1; /**< will retain setting */
unsigned int password : 1; /**< 3.1 password */
unsigned int username : 1; /**< 3.1 user name */
} bits; /**< connect flags byte (normal order) */
#endif
} MQTT_Connect_Header_Flags;
/**< connect flags byte */
/** connack flags byte */
typedef union {
uint8_t all; /**< all connack flags */
#if defined(REVERSED)
@@ -85,26 +80,24 @@ typedef union {
{
unsigned int sessionpresent : 1; /**< session present flag */
unsigned int : 7; /**< unused */
} bits;
} bits; /**< connect flags byte (reverse order) */
#else
struct {
unsigned int : 7;
/**< unused */
unsigned int sessionpresent : 1; /**< session present flag */
} bits;
unsigned int : 7; /**< unused */
unsigned int sessionpresent : 1; /**< session present flag */
} bits; /**< connect flags byte (normal order) */
#endif
} MQTT_Connack_Header_Flags;
/**< connack flags byte */
/** @brief Connect request response codes from server */
typedef enum {
CONNACK_CONNECTION_ACCEPTED = 0,
CONNACK_UNACCEPTABLE_PROTOCOL_VERSION_ERROR = 1,
CONNACK_IDENTIFIER_REJECTED_ERROR = 2,
CONNACK_SERVER_UNAVAILABLE_ERROR = 3,
CONNACK_BAD_USERDATA_ERROR = 4,
CONNACK_NOT_AUTHORIZED_ERROR = 5
} MQTT_Connack_Return_Codes; /**< Connect request response codes from server */
CONNACK_CONNECTION_ACCEPTED = 0, /**< Connection accepted */
CONNACK_UNACCEPTABLE_PROTOCOL_VERSION_ERROR = 1, /**< Unacceptable protocol version */
CONNACK_IDENTIFIER_REJECTED_ERROR = 2, /**< Client identifier rejected */
CONNACK_SERVER_UNAVAILABLE_ERROR = 3, /**< Server unavailable */
CONNACK_BAD_USERDATA_ERROR = 4, /**< Bad username */
CONNACK_NOT_AUTHORIZED_ERROR = 5 /**< Not authorized */
} MQTT_Connack_Return_Codes;
/**
* Determines the length of the MQTT connect packet that would be produced using the supplied connect options.
@@ -204,8 +197,8 @@ static IoT_Error_t _aws_iot_mqtt_serialize_connect(unsigned char *pTxBuf, size_t
if (pConnectParams->isWillMsgPresent)
{
flags.all |= 1 << 2;
flags.all |= pConnectParams->will.qos << 3;
flags.all |= pConnectParams->will.isRetained << 5;
flags.all |= (uint8_t) (pConnectParams->will.qos << 3);
flags.all |= (uint8_t) (pConnectParams->will.isRetained << 5);
}
if(pConnectParams->pPassword) {
@@ -437,8 +430,9 @@ static IoT_Error_t _aws_iot_mqtt_internal_connect(AWS_IoT_Client *pClient, const
FUNC_EXIT_RC(connack_rc);
}
/* Ensure that a ping request is sent after keepAliveInterval. */
pClient->clientStatus.isPingOutstanding = false;
countdown_sec(&pClient->pingTimer, pClient->clientData.keepAliveInterval);
countdown_sec(&pClient->pingReqTimer, pClient->clientData.keepAliveInterval);
FUNC_EXIT_RC(SUCCESS);
}
@@ -501,7 +495,7 @@ IoT_Error_t aws_iot_mqtt_connect(AWS_IoT_Client *pClient, const IoT_Client_Conne
*
* @return An IoT Error Type defining successful/failed send of the disconnect control packet.
*/
IoT_Error_t _aws_iot_mqtt_internal_disconnect(AWS_IoT_Client *pClient) {
static IoT_Error_t _aws_iot_mqtt_internal_disconnect(AWS_IoT_Client *pClient) {
/* We might wait for incomplete incoming publishes to complete */
Timer timer;
size_t serialized_len = 0;
@@ -527,7 +521,7 @@ IoT_Error_t _aws_iot_mqtt_internal_disconnect(AWS_IoT_Client *pClient) {
/* Clean network stack */
pClient->networkStack.disconnect(&(pClient->networkStack));
rc = pClient->networkStack.destroy(&(pClient->networkStack));
if(0 != rc) {
if(SUCCESS != rc) {
/* TLS Destroy failed, return error */
FUNC_EXIT_RC(FAILURE);
}
@@ -535,17 +529,6 @@ IoT_Error_t _aws_iot_mqtt_internal_disconnect(AWS_IoT_Client *pClient) {
FUNC_EXIT_RC(SUCCESS);
}
/**
* @brief Disconnect an MQTT Connection
*
* Called to send a disconnect message to the broker.
* This is the outer function which does the validations and calls the internal disconnect above
* to perform the actual operation. It is also responsible for client state changes
*
* @param pClient Reference to the IoT Client
*
* @return An IoT Error Type defining successful/failed send of the disconnect control packet.
*/
IoT_Error_t aws_iot_mqtt_disconnect(AWS_IoT_Client *pClient) {
ClientState clientState;
IoT_Error_t rc;
@@ -579,19 +562,6 @@ IoT_Error_t aws_iot_mqtt_disconnect(AWS_IoT_Client *pClient) {
FUNC_EXIT_RC(rc);
}
/**
* @brief MQTT Manual Re-Connection Function
*
* Called to establish an MQTT connection with the AWS IoT Service
* using parameters from the last time a connection was attempted
* Use after disconnect to start the reconnect process manually
* Makes only one reconnect attempt. Sets the client state to
* pending reconnect in case of failure
*
* @param pClient Reference to the IoT Client
*
* @return An IoT Error Type defining successful/failed connection
*/
IoT_Error_t aws_iot_mqtt_attempt_reconnect(AWS_IoT_Client *pClient) {
IoT_Error_t rc;
@@ -601,22 +571,28 @@ IoT_Error_t aws_iot_mqtt_attempt_reconnect(AWS_IoT_Client *pClient) {
FUNC_EXIT_RC(NULL_VALUE_ERROR);
}
if(aws_iot_mqtt_is_client_connected(pClient)) {
FUNC_EXIT_RC(NETWORK_ALREADY_CONNECTED_ERROR);
/* Only attempt a connect if not already connected. */
if(!aws_iot_mqtt_is_client_connected(pClient)) {
/* Ignoring return code. failures expected if network is disconnected */
aws_iot_mqtt_connect(pClient, NULL);
/* If still disconnected handle disconnect */
if(CLIENT_STATE_CONNECTED_IDLE != aws_iot_mqtt_get_client_state(pClient)) {
aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_DISCONNECTED_ERROR, CLIENT_STATE_PENDING_RECONNECT);
FUNC_EXIT_RC(NETWORK_ATTEMPTING_RECONNECT);
}
}
/* Ignoring return code. failures expected if network is disconnected */
rc = aws_iot_mqtt_connect(pClient, NULL);
/* If still disconnected handle disconnect */
if(CLIENT_STATE_CONNECTED_IDLE != aws_iot_mqtt_get_client_state(pClient)) {
aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_DISCONNECTED_ERROR, CLIENT_STATE_PENDING_RECONNECT);
FUNC_EXIT_RC(NETWORK_ATTEMPTING_RECONNECT);
else {
/* If already connected and no subscribe operation pending, then return
already connected error. */
if(CLIENT_STATE_CONNECTED_RESUBSCRIBE_IN_PROGRESS != aws_iot_mqtt_get_client_state(pClient)) {
FUNC_EXIT_RC(NETWORK_ALREADY_CONNECTED_ERROR);
}
}
rc = aws_iot_mqtt_resubscribe(pClient);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
FUNC_EXIT_RC(NETWORK_ATTEMPTING_RECONNECT);
}
FUNC_EXIT_RC(NETWORK_RECONNECTED);
@@ -242,23 +242,6 @@ static IoT_Error_t _aws_iot_mqtt_internal_publish(AWS_IoT_Client *pClient, const
FUNC_EXIT_RC(SUCCESS);
}
/**
* @brief Publish an MQTT message on a topic
*
* Called to publish an MQTT message on a topic.
* @note Call is blocking. In the case of a QoS 0 message the function returns
* after the message was successfully passed to the TLS layer. In the case of QoS 1
* the function returns after the receipt of the PUBACK control packet.
* This is the outer function which does the validations and calls the internal publish above
* to perform the actual operation. It is also responsible for client state changes
*
* @param pClient Reference to the IoT Client
* @param pTopicName Topic Name to publish to
* @param topicNameLen Length of the topic name
* @param pParams Pointer to Publish Message parameters
*
* @return An IoT Error Type defining successful/failed publish
*/
IoT_Error_t aws_iot_mqtt_publish(AWS_IoT_Client *pClient, const char *pTopicName, uint16_t topicNameLen,
IoT_Publish_Message_Params *pParams) {
IoT_Error_t rc, pubRc;
@@ -303,7 +286,7 @@ IoT_Error_t aws_iot_mqtt_publish(AWS_IoT_Client *pClient, const char *pTopicName
* @param pTopicName returned String - the MQTT topic in the publish
* @param topicNameLen returned uint16_t - the length of the MQTT topic in the publish
* @param payload returned byte buffer - the MQTT publish payload
* @param payloadlen returned size_t - the length of the MQTT payload
* @param payloadLen returned size_t - the length of the MQTT payload
* @param pRxBuf the raw buffer data, of the correct length determined by the remaining length field
* @param rxBufLen the length in bytes of the data in the supplied buffer
*
@@ -195,11 +195,11 @@ static uint32_t _aws_iot_mqtt_get_free_message_handler_index(AWS_IoT_Client *pCl
* @warning pTopicName and pApplicationHandlerData need to be static in memory.
*
* @param pClient Reference to the IoT Client
* @param pTopicName Topic Name to publish to. pTopicName needs to be static in memory since
* @param pTopicName Topic Name to publish to. pTopicName needs to be static in memory since
* no malloc are performed by the SDK
* @param topicNameLen Length of the topic name
* @param pApplicationHandler_t Reference to the handler function for this subscription
* @param pApplicationHandlerData Point to data passed to the callback.
* @param pApplicationHandlerData Point to data passed to the callback.
* pApplicationHandlerData also needs to be static in memory since no malloc are performed by the SDK
*
* @return An IoT Error Type defining successful/failed subscription
@@ -273,26 +273,6 @@ static IoT_Error_t _aws_iot_mqtt_internal_subscribe(AWS_IoT_Client *pClient, con
FUNC_EXIT_RC(SUCCESS);
}
/**
* @brief Subscribe to an MQTT topic.
*
* Called to send a subscribe message to the broker requesting a subscription
* to an MQTT topic. This is the outer function which does the validations and
* calls the internal subscribe above to perform the actual operation.
* It is also responsible for client state changes
* @note Call is blocking. The call returns after the receipt of the SUBACK control packet.
* @warning pTopicName and pApplicationHandlerData need to be static in memory.
*
* @param pClient Reference to the IoT Client
* @param pTopicName Topic Name to publish to. pTopicName needs to be static in memory since
* no malloc are performed by the SDK
* @param topicNameLen Length of the topic name
* @param pApplicationHandler_t Reference to the handler function for this subscription
* @param pApplicationHandlerData Point to data passed to the callback.
* pApplicationHandlerData also needs to be static in memory since no malloc are performed by the SDK
*
* @return An IoT Error Type defining successful/failed subscription
*/
IoT_Error_t aws_iot_mqtt_subscribe(AWS_IoT_Client *pClient, const char *pTopicName, uint16_t topicNameLen,
QoS qos, pApplicationHandler_t pApplicationHandler, void *pApplicationHandlerData) {
ClientState clientState;
@@ -361,6 +341,12 @@ static IoT_Error_t _aws_iot_mqtt_internal_resubscribe(AWS_IoT_Client *pClient) {
continue;
}
/* Do not attempt to subscribe to topics which have already been subscribed
to in the previous re-subscribe attempts. */
if(pClient->clientData.messageHandlers[itr].resubscribed == 1) {
continue;
}
init_timer(&timer);
countdown_ms(&timer, pClient->clientData.commandTimeoutMs);
@@ -391,26 +377,18 @@ static IoT_Error_t _aws_iot_mqtt_internal_resubscribe(AWS_IoT_Client *pClient) {
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
/* Record that this topic has been subscribed to, so that we do not
* attempt to subscribe again to the same topic. */
pClient->clientData.messageHandlers[itr].resubscribed = 1;
}
FUNC_EXIT_RC(SUCCESS);
}
/**
* @brief Subscribe to an MQTT topic.
*
* Called to send a subscribe message to the broker requesting a subscription
* to an MQTT topic.
* This is the outer function which does the validations and calls the internal resubscribe above
* to perform the actual operation. It is also responsible for client state changes
* @note Call is blocking. The call returns after the receipt of the SUBACK control packet.
*
* @param pClient Reference to the IoT Client
*
* @return An IoT Error Type defining successful/failed subscription
*/
IoT_Error_t aws_iot_mqtt_resubscribe(AWS_IoT_Client *pClient) {
IoT_Error_t rc, resubRc;
ClientState currentState = aws_iot_mqtt_get_client_state(pClient);
FUNC_ENTRY;
@@ -422,22 +400,31 @@ IoT_Error_t aws_iot_mqtt_resubscribe(AWS_IoT_Client *pClient) {
FUNC_EXIT_RC(NETWORK_DISCONNECTED_ERROR);
}
if(CLIENT_STATE_CONNECTED_IDLE != aws_iot_mqtt_get_client_state(pClient)) {
FUNC_EXIT_RC(MQTT_CLIENT_NOT_IDLE_ERROR);
/* At this point, the client state should be either CLIENT_STATE_CONNECTED_IDLE
or CLIENT_STATE_CONNECTED_RESUBSCRIBE_IN_PROGRESS. The former means that it
is the first re-subscribe attempt while the latter means that it is second
or subsequent re-subscribe attempt. */
if((CLIENT_STATE_CONNECTED_IDLE != currentState) && (CLIENT_STATE_CONNECTED_RESUBSCRIBE_IN_PROGRESS != currentState)) {
FUNC_EXIT_RC(MQTT_UNEXPECTED_CLIENT_STATE_ERROR);
}
rc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTED_IDLE,
CLIENT_STATE_CONNECTED_RESUBSCRIBE_IN_PROGRESS);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
/* If it is the first re-subscribe attempt (i.e. client state is CLIENT_STATE_CONNECTED_IDLE),
set the client state to CLIENT_STATE_CONNECTED_RESUBSCRIBE_IN_PROGRESS. */
if(CLIENT_STATE_CONNECTED_IDLE == currentState) {
rc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTED_IDLE, CLIENT_STATE_CONNECTED_RESUBSCRIBE_IN_PROGRESS);
if(SUCCESS != rc) {
FUNC_EXIT_RC(rc);
}
}
resubRc = _aws_iot_mqtt_internal_resubscribe(pClient);
rc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTED_RESUBSCRIBE_IN_PROGRESS,
CLIENT_STATE_CONNECTED_IDLE);
if(SUCCESS == resubRc && SUCCESS != rc) {
resubRc = rc;
/* It is possible that the subscribe operation fails, do not change the state
in that case so that the subscribe is attempted again in the next iteration
of yield. */
if(SUCCESS == resubRc) {
resubRc = aws_iot_mqtt_set_client_state(pClient, CLIENT_STATE_CONNECTED_RESUBSCRIBE_IN_PROGRESS, CLIENT_STATE_CONNECTED_IDLE);
}
FUNC_EXIT_RC(resubRc);
@@ -446,4 +433,3 @@ IoT_Error_t aws_iot_mqtt_resubscribe(AWS_IoT_Client *pClient) {
#ifdef __cplusplus
}
#endif
@@ -196,21 +196,6 @@ static IoT_Error_t _aws_iot_mqtt_internal_unsubscribe(AWS_IoT_Client *pClient, c
FUNC_EXIT_RC(SUCCESS);
}
/**
* @brief Unsubscribe to an MQTT topic.
*
* Called to send an unsubscribe message to the broker requesting removal of a subscription
* to an MQTT topic.
* @note Call is blocking. The call returns after the receipt of the UNSUBACK control packet.
* This is the outer function which does the validations and calls the internal unsubscribe above
* to perform the actual operation. It is also responsible for client state changes
*
* @param pClient Reference to the IoT Client
* @param pTopicName Topic Name to publish to
* @param topicNameLen Length of the topic name
*
* @return An IoT Error Type defining successful/failed unsubscribe call
*/
IoT_Error_t aws_iot_mqtt_unsubscribe(AWS_IoT_Client *pClient, const char *pTopicFilter, uint16_t topicFilterLen) {
IoT_Error_t rc, unsubRc;
ClientState clientState;
@@ -247,4 +232,3 @@ IoT_Error_t aws_iot_mqtt_unsubscribe(AWS_IoT_Client *pClient, const char *pTopic
#ifdef __cplusplus
}
#endif
@@ -61,12 +61,16 @@ static IoT_Error_t _aws_iot_mqtt_handle_disconnect(AWS_IoT_Client *pClient) {
_aws_iot_mqtt_force_client_disconnect(pClient);
}
pClient->clientStatus.clientState = CLIENT_STATE_DISCONNECTED_ERROR;
if(NULL != pClient->clientData.disconnectHandler) {
pClient->clientData.disconnectHandler(pClient, pClient->clientData.disconnectHandlerData);
}
/* Reset to 0 since this was not a manual disconnect */
pClient->clientStatus.clientState = CLIENT_STATE_DISCONNECTED_ERROR;
if (pClient->clientStatus.clientState == CLIENT_STATE_CONNECTED_IDLE) {
FUNC_EXIT_RC(SUCCESS);
}
FUNC_EXIT_RC(NETWORK_DISCONNECTED_ERROR);
}
@@ -123,14 +127,27 @@ static IoT_Error_t _aws_iot_mqtt_keep_alive(AWS_IoT_Client *pClient) {
FUNC_EXIT_RC(SUCCESS);
}
if(!has_timer_expired(&pClient->pingTimer)) {
FUNC_EXIT_RC(SUCCESS);
}
if(pClient->clientStatus.isPingOutstanding) {
rc = _aws_iot_mqtt_handle_disconnect(pClient);
FUNC_EXIT_RC(rc);
/* We are waiting for a PINGRESP from the broker. If the pingRespTimer,
* has expired, it indicates that the transport layer connection is
* lost and therefore, we initiate MQTT disconnect (which will triggger)
* the re-connect workflow, if enabled. If the pingRespTimer is not
* expired, there is nothing to do and we continue waiting for PINGRESP. */
if(has_timer_expired(&pClient->pingRespTimer)) {
rc = _aws_iot_mqtt_handle_disconnect(pClient);
FUNC_EXIT_RC(rc);
} else {
FUNC_EXIT_RC(SUCCESS);
}
} else {
/* We are not waiting for a PINGRESP from the broker. If the
* pingReqTimer has expired, we send a PINGREQ. Otherwise, there is
* nothing to do. */
if(!has_timer_expired(&pClient->pingReqTimer)) {
FUNC_EXIT_RC(SUCCESS);
}
}
/* there is no ping outstanding - send one */
init_timer(&timer);
@@ -152,8 +169,10 @@ static IoT_Error_t _aws_iot_mqtt_keep_alive(AWS_IoT_Client *pClient) {
}
pClient->clientStatus.isPingOutstanding = true;
/* start a timer to wait for PINGRESP from server */
countdown_sec(&pClient->pingTimer, pClient->clientData.keepAliveInterval);
/* Start a timer to wait for PINGRESP from server. */
countdown_sec(&pClient->pingRespTimer, pClient->clientData.keepAliveInterval);
/* Start a timer to keep track of when to send the next PINGREQ. */
countdown_sec(&pClient->pingReqTimer, pClient->clientData.keepAliveInterval);
FUNC_EXIT_RC(SUCCESS);
}
@@ -180,6 +199,7 @@ static IoT_Error_t _aws_iot_mqtt_keep_alive(AWS_IoT_Client *pClient) {
static IoT_Error_t _aws_iot_mqtt_internal_yield(AWS_IoT_Client *pClient, uint32_t timeout_ms) {
IoT_Error_t yieldRc = SUCCESS;
int itr = 0;
uint8_t packet_type;
ClientState clientState;
@@ -192,7 +212,13 @@ static IoT_Error_t _aws_iot_mqtt_internal_yield(AWS_IoT_Client *pClient, uint32_
// evaluate timeout at the end of the loop to make sure the actual yield runs at least once
do {
clientState = aws_iot_mqtt_get_client_state(pClient);
if(CLIENT_STATE_PENDING_RECONNECT == clientState) {
/* If the client state is pending reconnect or resubscribe in progress,
we keep retrying _aws_iot_mqtt_handle_reconnect. This function only
attempts to connect if not already connected thereby ensuring that the
subsequent invocations only attempt remaining subscribes. */
if((CLIENT_STATE_PENDING_RECONNECT == clientState) ||
(CLIENT_STATE_CONNECTED_RESUBSCRIBE_IN_PROGRESS == clientState)) {
if(AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL < pClient->clientData.currentReconnectWaitInterval) {
yieldRc = NETWORK_RECONNECT_TIMED_OUT_ERROR;
break;
@@ -224,6 +250,11 @@ static IoT_Error_t _aws_iot_mqtt_internal_yield(AWS_IoT_Client *pClient, uint32_
pClient->clientData.currentReconnectWaitInterval = AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL;
countdown_ms(&(pClient->reconnectDelayTimer), pClient->clientData.currentReconnectWaitInterval);
for(itr = 0; itr < AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS; itr++) {
pClient->clientData.messageHandlers[itr].resubscribed = 0;
}
/* Depending on timer values, it is possible that yield timer has expired
* Set to rc to attempting reconnect to inform client that autoreconnect
* attempt has started */
@@ -239,25 +270,6 @@ static IoT_Error_t _aws_iot_mqtt_internal_yield(AWS_IoT_Client *pClient, uint32_
FUNC_EXIT_RC(yieldRc);
}
/**
* @brief Yield to the MQTT client
*
* Called to yield the current thread to the underlying MQTT client. This time is used by
* the MQTT client to manage PING requests to monitor the health of the TCP connection as
* well as periodically check the socket receive buffer for subscribe messages. Yield()
* must be called at a rate faster than the keepalive interval. It must also be called
* at a rate faster than the incoming message rate as this is the only way the client receives
* processing time to manage incoming messages.
* This is the outer function which does the validations and calls the internal yield above
* to perform the actual operation. It is also responsible for client state changes
*
* @param pClient Reference to the IoT Client
* @param timeout_ms Maximum number of milliseconds to pass thread execution to the client.
*
* @return An IoT Error Type defining successful/failed client processing.
* If this call results in an error it is likely the MQTT connection has dropped.
* iot_is_mqtt_connected can be called to confirm.
*/
IoT_Error_t aws_iot_mqtt_yield(AWS_IoT_Client *pClient, uint32_t timeout_ms) {
IoT_Error_t rc, yieldRc;
ClientState clientState;
@@ -272,9 +284,11 @@ IoT_Error_t aws_iot_mqtt_yield(AWS_IoT_Client *pClient, uint32_t timeout_ms) {
FUNC_EXIT_RC(NETWORK_MANUALLY_DISCONNECTED);
}
/* If we are in the pending reconnect state, skip other checks.
* Pending reconnect state is only set when auto-reconnect is enabled */
if(CLIENT_STATE_PENDING_RECONNECT != clientState) {
/* If we are in the pending reconnect or resubscribe in progress state, skip other checks.
* Pending reconnect or resubscribe in progress state is only set when auto-reconnect
* is enabled */
if((CLIENT_STATE_PENDING_RECONNECT != clientState) &&
(CLIENT_STATE_CONNECTED_RESUBSCRIBE_IN_PROGRESS != clientState)) {
/* Check if network is disconnected and auto-reconnect is not enabled */
if(!aws_iot_mqtt_is_client_connected(pClient)) {
FUNC_EXIT_RC(NETWORK_DISCONNECTED_ERROR);
@@ -308,4 +322,3 @@ IoT_Error_t aws_iot_mqtt_yield(AWS_IoT_Client *pClient, uint32_t timeout_ms) {
#ifdef __cplusplus
}
#endif
@@ -431,13 +431,13 @@ static IoT_Error_t UpdateValueIfNoObject(const char *pJsonString, jsonStruct_t *
bool isJsonKeyMatchingAndUpdateValue(const char *pJsonDocument, void *pJsonHandler, int32_t tokenCount,
jsonStruct_t *pDataStruct, uint32_t *pDataLength, int32_t *pDataPosition) {
int32_t i;
int32_t i, metadataEnd;
uint32_t dataLength;
jsmntok_t dataToken;
IOT_UNUSED(pJsonHandler);
for(i = 1; i < tokenCount; i++) {
for(i = 1; i < tokenCount; ) {
if(jsoneq(pJsonDocument, &(jsonTokenStruct[i]), pDataStruct->pKey) == 0) {
dataToken = jsonTokenStruct[i + 1];
dataLength = (uint32_t) (dataToken.end - dataToken.start);
@@ -446,7 +446,32 @@ bool isJsonKeyMatchingAndUpdateValue(const char *pJsonDocument, void *pJsonHandl
*pDataLength = dataLength;
return true;
} else if(jsoneq(pJsonDocument, &(jsonTokenStruct[i]), "metadata") == 0) {
return false;
/* Sanity check: must not be at the last key in the json object. */
if(i >= tokenCount-2)
{
return false;
}
/* Record where the metadata object ends. */
metadataEnd = jsonTokenStruct[i+1].end;
/* Skip past the "metadata" key and jsmn object element. */
i+= 2;
/* Skip past every key inside "metadata". Keys inside "metadata" have
* have an end character before the end of the metadata object.
*/
while(jsonTokenStruct[i].end < metadataEnd)
{
i++;
}
}
else
{
/* Only increment the loop counter if the current object doesn't
* match AND isn't "metadata".
*/
i++;
}
}
return false;
@@ -495,7 +520,7 @@ bool extractClientToken(const char *pJsonDocument, size_t jsonSize, char *pExtra
for(i = 1; i < tokenCount; i++) {
if(jsoneq(pJsonDocument, &jsonTokenStruct[i], SHADOW_CLIENT_TOKEN_STRING) == 0) {
ClientJsonToken = jsonTokenStruct[i + 1];
length = (uint8_t) (ClientJsonToken.end - ClientJsonToken.start);
length = (size_t) (ClientJsonToken.end - ClientJsonToken.start);
if (clientTokenSize >= length + 1)
{
strncpy( pExtractedClientToken, pJsonDocument + ClientJsonToken.start, length);
@@ -22,11 +22,12 @@ PLATFORM_DIR = $(IOT_CLIENT_DIR)/platform/linux
#MbedTLS directory
TEMP_MBEDTLS_SRC_DIR = $(IOT_CLIENT_DIR)/external_libs/mbedTLS
TLS_LIB_DIR = $(TEMP_MBEDTLS_SRC_DIR)/library
CRYPTO_LIB_DIR = $(TEMP_MBEDTLS_SRC_DIR)/library
TLS_INCLUDE_DIR = -I $(TEMP_MBEDTLS_SRC_DIR)/include
EXTERNAL_LIBS += -L$(TLS_LIB_DIR)
LD_FLAG += -Wl,-rpath,$(TLS_LIB_DIR)
LD_FLAG += -ldl $(TLS_LIB_DIR)/libmbedtls.a $(TLS_LIB_DIR)/libmbedcrypto.a $(TLS_LIB_DIR)/libmbedx509.a -lpthread
LD_FLAG += -ldl $(TLS_LIB_DIR)/libmbedtls.a $(CRYPTO_LIB_DIR)/libmbedcrypto.a $(TLS_LIB_DIR)/libmbedx509.a -lpthread
# Logging level control
#LOG_FLAGS += -DENABLE_IOT_DEBUG
@@ -93,7 +94,7 @@ app:
$(PRE_MAKE_CMDS)
$(DEBUG)$(MAKE_CMD)
$(DEBUG)$(MAKE_MT_CMD)
tests:
./$(APP_NAME)
./$(MT_APP_NAME)
@@ -68,6 +68,10 @@ void setTLSRxBufferForUnsuback(void);
void setTLSRxBufferForPingresp(void);
void setTLSRxBufferForError(IoT_Error_t error);
void setTLSTxBufferForError(IoT_Error_t error);
void setTLSRxBufferForConnackAndSuback(IoT_Client_Connect_Params *conParams, unsigned char sessionPresent,
char *topicName, size_t topicNameLen, QoS qos);
@@ -82,3 +82,5 @@ TEST_GROUP_C_WRAPPER(ConnectTests, ConnectDisconnectConnect)
TEST_GROUP_C_WRAPPER(ConnectTests, cleanSessionInitSubscribers)
/* B:28 - Connect attempt, power cycle with clean session false */
TEST_GROUP_C_WRAPPER(ConnectTests, PowerCycleWithCleanSessionFalse)
/* B:29 - Reconnect attempt succeeds, but resubscribes fail */
TEST_GROUP_C_WRAPPER(ConnectTests, ReconnectAndResubscribe)
@@ -29,6 +29,8 @@
#include "aws_iot_log.h"
#include "aws_iot_mqtt_client_common_internal.h"
static bool unitTestIsMqttConnected = false;
static IoT_Client_Init_Params initParams;
@@ -61,9 +63,8 @@ static void iot_subscribe_callback_handler(AWS_IoT_Client *pClient, char *topicN
}
TEST_GROUP_C_SETUP(ConnectTests) {
IoT_Error_t rc = SUCCESS;
unitTestIsMqttConnected = false;
rc = aws_iot_mqtt_disconnect(&iotClient);
( void ) aws_iot_mqtt_disconnect(&iotClient);
ResetTLSBuffer();
ResetInvalidParameters();
}
@@ -718,3 +719,74 @@ TEST_C(ConnectTests, PowerCycleWithCleanSessionFalse) {
IOT_DEBUG("-->Success - B:28 - Connect attempt, power cycle with clean session false \n");
}
/* B:29 - Reconnect attempt succeeds, but resubscribes fail.
* This test verifies the behaviour that if a subscribe operation fails after
* connect during the auto-reconnect sequence, the client must not disconnect
* and must only re-attempt the subscribe operation. */
TEST_C(ConnectTests, ReconnectAndResubscribe) {
IoT_Error_t rc = SUCCESS;
int itr = 0;
char subTestTopic[12] = { 0 };
uint16_t subTestTopicLen = 0;
IoT_Publish_Message_Params publish = { 0 };
IOT_DEBUG("-->Running Connect Tests - B:29 - Reconnect attempt succeeds, but resubscribes fail \n");
#if AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS < 3
#error "ReconnectAndResubscribe needs at least 3 subscription handlers to run"
#endif
// 1. Initialize client
InitMQTTParamsSetup(&initParams, AWS_IOT_MQTT_HOST, AWS_IOT_MQTT_PORT, true, NULL);
rc = aws_iot_mqtt_init(&iotClient, &initParams);
CHECK_EQUAL_C_INT(SUCCESS, rc);
ResetTLSBuffer();
// 2. Establish connection
ConnectMQTTParamsSetup(&connectParams, AWS_IOT_MQTT_CLIENT_ID, (uint16_t) strlen(AWS_IOT_MQTT_CLIENT_ID));
connectParams.isCleanSession = true;
setTLSRxBufferForConnack(&connectParams, 0, 0);
rc = aws_iot_mqtt_connect(&iotClient, &connectParams);
CHECK_EQUAL_C_INT(SUCCESS, rc);
// 3. Add 3 subscriptions
for(itr = 0; itr < 3; itr++)
{
snprintf(subTestTopic, 12, "sdk/topic%d", itr + 1);
subTestTopicLen = (uint16_t) strlen(subTestTopic);
setTLSRxBufferForSuback(subTestTopic, subTestTopicLen, QOS0, testPubMsgParams);
rc = aws_iot_mqtt_subscribe(&iotClient, subTestTopic, subTestTopicLen, QOS0, iot_subscribe_callback_handler,
NULL);
CHECK_EQUAL_C_INT(SUCCESS, rc);
}
// 4. Trigger a reconnect by mocking NETWORK_SSL_READ_ERROR and calling yield.
// Place a CONNACK and SUBACK in the Rx buffer so that connect and 1 subscribe
// succeed. Note that the CONNACK and SUBACK placed in the Rx buffer are not
// effected by the mocked error as it does not change thr content of the Rx
// buffer.
setTLSRxBufferForError(NETWORK_SSL_READ_ERROR);
setTLSRxBufferForConnackAndSuback(&connectParams, 0, "sdk/topic0", 10, QOS0);
rc = aws_iot_mqtt_yield(&iotClient, AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL * 2);
// 5. Check results of yield call. As only 1 SUBACK was present in the Rx
// buffer, 2 resubscribes must fail. Client should be in a pending
// resubscribe state and the auto reconnect interval should have doubled.
CHECK_EQUAL_C_INT(NETWORK_ATTEMPTING_RECONNECT, rc);
CHECK_EQUAL_C_INT(1, iotClient.clientData.messageHandlers[0].resubscribed);
CHECK_EQUAL_C_INT(0, iotClient.clientData.messageHandlers[1].resubscribed);
CHECK_EQUAL_C_INT(0, iotClient.clientData.messageHandlers[2].resubscribed);
CHECK_EQUAL_C_INT(CLIENT_STATE_CONNECTED_RESUBSCRIBE_IN_PROGRESS, aws_iot_mqtt_get_client_state(&iotClient));
CHECK_EQUAL_C_INT(2 * AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL, (int) iotClient.clientData.currentReconnectWaitInterval);
// 6. Add 2 more SUBACKs to the Rx buffer to complete the resubscribe.
setTLSRxBufferForDoubleSuback("sdk/topic1", 10, QOS0, publish);
rc = aws_iot_mqtt_yield(&iotClient, 2 * AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL * 2);
CHECK_EQUAL_C_INT(CLIENT_STATE_CONNECTED_IDLE, aws_iot_mqtt_get_client_state(&iotClient));
CHECK_EQUAL_C_INT(1, iotClient.clientData.messageHandlers[0].resubscribed);
CHECK_EQUAL_C_INT(1, iotClient.clientData.messageHandlers[1].resubscribed);
CHECK_EQUAL_C_INT(1, iotClient.clientData.messageHandlers[2].resubscribed);
IOT_DEBUG("-->Success - B:29 - Reconnect attempt succeeds, but resubscribes fail \n");
}
@@ -247,6 +247,14 @@ void setTLSRxBufferForPingresp(void) {
RxIndex = 0;
}
void setTLSRxBufferForError(IoT_Error_t error) {
RxBuffer.mockedError = error;
}
void setTLSTxBufferForError(IoT_Error_t error) {
TxBuffer.mockedError = error;
}
void ResetTLSBuffer(void) {
size_t i;
RxBuffer.len = 0;
@@ -65,9 +65,9 @@ TEST_GROUP_C_WRAPPER(SubscribeTests, subscribeMalformedResponse)
/* C:16 - Subscribe, multiple topics, messages on each topic */
TEST_GROUP_C_WRAPPER(SubscribeTests, SubscribeToMultipleTopicsSuccess)
/* C:17 - Subscribe, max topics, messages on each topic */
TEST_GROUP_C_WRAPPER(SubscribeTests, SubcribeToMaxAllowedTopicsSuccess)
TEST_GROUP_C_WRAPPER(SubscribeTests, SubscribeToMaxAllowedTopicsSuccess)
/* C:18 - Subscribe, max topics, another subscribe */
TEST_GROUP_C_WRAPPER(SubscribeTests, SubcribeToMaxPlusOneAllowedTopicsFailure)
TEST_GROUP_C_WRAPPER(SubscribeTests, SubscribeToMaxPlusOneAllowedTopicsFailure)
/* C:19 - Subscribe, '#' not last character in topic name, Failure */
TEST_GROUP_C_WRAPPER(SubscribeTests, subscribeTopicWithHashkeyAllSubTopicSuccess)
@@ -69,7 +69,7 @@ static void iot_subscribe_callback_handler1(AWS_IoT_Client *pClient, char *topic
char *tmp = params->payload;
unsigned int i;
printf("callback topic %s\n", topicName);
printf("callback topic %.*s\n", topicNameLen, topicName);
for(i = 0; i < (params->payloadLen); i++) {
CallbackMsgString1[i] = tmp[i];
}
@@ -363,7 +363,7 @@ TEST_C(SubscribeTests, SubscribeToMultipleTopicsSuccess) {
IOT_DEBUG("-->Success - C:16 - Subscribe, multiple topics, messages on each topic \n");
}
/* C:17 - Subscribe, max topics, messages on each topic */
TEST_C(SubscribeTests, SubcribeToMaxAllowedTopicsSuccess) {
TEST_C(SubscribeTests, SubscribeToMaxAllowedTopicsSuccess) {
IoT_Error_t rc = SUCCESS;
char expectedCallbackString[] = "topics sdk/Test1";
char expectedCallbackString2[] = "topics sdk/Test2";
@@ -422,7 +422,7 @@ TEST_C(SubscribeTests, SubcribeToMaxAllowedTopicsSuccess) {
IOT_DEBUG("-->Success - C:17 - Subscribe, max topics, messages on each topic \n");
}
/* C:18 - Subscribe, max topics, another subscribe */
TEST_C(SubscribeTests, SubcribeToMaxPlusOneAllowedTopicsFailure) {
TEST_C(SubscribeTests, SubscribeToMaxPlusOneAllowedTopicsFailure) {
IoT_Error_t rc = SUCCESS;
IOT_DEBUG("-->Running Subscribe Tests - C:18 - Subscribe, max topics, another subscribe \n");
@@ -52,3 +52,6 @@ TEST_GROUP_C_WRAPPER(YieldTests, disconnectAutoReconnectSuccess)
TEST_GROUP_C_WRAPPER(YieldTests, disconnectManualAutoReconnect)
/* G:12 - Yield, resubscribe to all topics on reconnect */
TEST_GROUP_C_WRAPPER(YieldTests, resubscribeSuccessfulReconnect)
/* G:13 - Delayed Ping response. */
TEST_GROUP_C_WRAPPER(YieldTests, delayedPingResponse)
@@ -450,3 +450,44 @@ TEST_C(YieldTests, resubscribeSuccessfulReconnect) {
IOT_DEBUG("-->Success - G:12 - Yield, resubscribe to all topics on reconnect \n");
}
/* G:13 - Delayed Ping response. */
TEST_C(YieldTests, delayedPingResponse)
{
IoT_Error_t rc = FAILURE;
IOT_DEBUG("-->Running Yield Tests - G:13 - Delayed Ping response. \n");
ResetTLSBuffer();
/* Sleep for keep alive interval to allow the first ping to be sent out. */
sleep(iotClient.clientData.keepAliveInterval);
rc = aws_iot_mqtt_yield(&iotClient, 100);
CHECK_EQUAL_C_INT(SUCCESS, rc);
CHECK_EQUAL_C_INT(true, isLastTLSTxMessagePingreq());
/* Sleep for half of the keep alive interval to simulate a delayed ping
* response. */
sleep(iotClient.clientData.keepAliveInterval / 2);
/* Receive the delayed ping response. */
ResetTLSBuffer();
setTLSRxBufferForPingresp();
rc = aws_iot_mqtt_yield(&iotClient, 100);
CHECK_EQUAL_C_INT(SUCCESS, rc);
/* Sleep for half of the keep alive interval - at this time a ping request
* must be sent out because a full keep alive interval has passed since we
* last sent a ping request. This ensures that the timer which tracks when
* to send a ping request does not incorrectly get reset upon receipt of a
* ping response. +1 is done to ensure that we don't hit boundry condition
* where timer does not expire because the time elasped is exactly equal to
* the keep alive interval (as opposed to more than that). */
sleep(iotClient.clientData.keepAliveInterval / 2 + 1);
ResetTLSBuffer();
rc = aws_iot_mqtt_yield(&iotClient, 100);
CHECK_EQUAL_C_INT(SUCCESS, rc);
CHECK_EQUAL_C_INT(true, isLastTLSTxMessagePingreq());
IOT_DEBUG("-->Success - G:13 - Delayed Ping response. \n");
}
@@ -111,9 +111,19 @@ IoT_Error_t iot_tls_write(Network *pNetwork, unsigned char *pMsg, size_t len, Ti
uint8_t firstPacketByte;
size_t mqttPacketLength;
size_t variableHeaderStart;
IoT_Error_t status = SUCCESS;
IOT_UNUSED(pNetwork);
IOT_UNUSED(timer);
if(TxBuffer.mockedError != SUCCESS ) {
status = TxBuffer.mockedError;
/* Clear the error before returning. */
TxBuffer.mockedError = SUCCESS;
return status;
}
for(i = 0; (i < len) && left_ms(timer) > 0; i++) {
TxBuffer.pBuffer[i] = pMsg[i];
}
@@ -151,7 +161,7 @@ IoT_Error_t iot_tls_write(Network *pNetwork, unsigned char *pMsg, size_t len, Ti
LastPublishMessagePayload[lastPublishMessagePayloadLen] = 0;
}
return SUCCESS;
return status;
}
static unsigned char isTimerExpired(struct timeval target_time) {
@@ -171,9 +181,20 @@ static unsigned char isTimerExpired(struct timeval target_time) {
}
IoT_Error_t iot_tls_read(Network *pNetwork, unsigned char *pMsg, size_t len, Timer *pTimer, size_t *read_len) {
IoT_Error_t status = SUCCESS;
IOT_UNUSED(pNetwork);
IOT_UNUSED(pTimer);
if(RxBuffer.mockedError != SUCCESS) {
status = RxBuffer.mockedError;
/* Clear the error before returning. */
RxBuffer.mockedError = SUCCESS;
return status;
}
if(RxIndex > TLSMaxBufferSize - 1) {
RxIndex = TLSMaxBufferSize - 1;
}
@@ -188,7 +209,7 @@ IoT_Error_t iot_tls_read(Network *pNetwork, unsigned char *pMsg, size_t len, Tim
*read_len = len;
}
return SUCCESS;
return status;
}
IoT_Error_t iot_tls_disconnect(Network *pNetwork) {
@@ -35,8 +35,8 @@ size_t lastPublishMessageTopicLen;
char LastPublishMessagePayload[TLSMaxBufferSize];
size_t lastPublishMessagePayloadLen;
TlsBuffer RxBuffer = {.pBuffer = RxBuf,.len = 512, .NoMsgFlag=1, .expiry_time = {0, 0}, .BufMaxSize = TLSMaxBufferSize};
TlsBuffer TxBuffer = {.pBuffer = TxBuf,.len = 512, .NoMsgFlag=1, .expiry_time = {0, 0}, .BufMaxSize = TLSMaxBufferSize};
TlsBuffer RxBuffer = {.pBuffer = RxBuf,.len = 512, .NoMsgFlag=1, .expiry_time = {0, 0}, .BufMaxSize = TLSMaxBufferSize, .mockedError = SUCCESS};
TlsBuffer TxBuffer = {.pBuffer = TxBuf,.len = 512, .NoMsgFlag=1, .expiry_time = {0, 0}, .BufMaxSize = TLSMaxBufferSize, .mockedError = SUCCESS};
size_t RxIndex = 0;
@@ -36,6 +36,7 @@ typedef struct {
bool NoMsgFlag;
struct timeval expiry_time;
size_t BufMaxSize;
IoT_Error_t mockedError;
} TlsBuffer;
@@ -7,3 +7,7 @@ CONFIG_FATFS_LFN_HEAP=y
# Enable TLS asymmetric in/out content length
CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y
# Example configs
CONFIG_EXAMPLE_WIFI_SSID="MYSSID"
CONFIG_EXAMPLE_WIFI_PASSWORD="MYPASS"
@@ -12,7 +12,3 @@ platform = espressif32
framework = espidf
board = esp32dev
monitor_speed = 115200
build_flags =
; https://docs.espressif.com/projects/esp-idf/en/latest/get-started/get-started-wrover-kit.html#rgb-led
-D CONFIG_BLINK_GPIO=2
+8 -11
View File
@@ -7,23 +7,20 @@
; Please visit documentation for the other options and examples
; http://docs.platformio.org/page/projectconf.html
[env:nano32]
[env]
platform = espressif32
framework = espidf
board = nano32
build_flags = -DCONFIG_WIFI_SSID=\"ESP_AP\" -DCONFIG_WIFI_PASSWORD=\"MYPASS\"
monitor_speed = 115200
board_build.embed_txtfiles =
src/certs/coap_ca.pem
src/certs/coap_server.crt
src/certs/coap_server.key
[env:nano32]
board = nano32
[env:esp-wrover-kit]
platform = espressif32
framework = espidf
board = esp-wrover-kit
build_flags = -DCONFIG_WIFI_SSID=\"ESP_AP\" -DCONFIG_WIFI_PASSWORD=\"MYPASS\"
monitor_speed = 115200
[env:esp32dev]
platform = espressif32
framework = espidf
board = esp32dev
build_flags = -DCONFIG_WIFI_SSID=\"ESP_AP\" -DCONFIG_WIFI_PASSWORD=\"MYPASS\"
monitor_speed = 115200
@@ -0,0 +1,2 @@
CONFIG_EXAMPLE_WIFI_SSID="MYSSID"
CONFIG_EXAMPLE_WIFI_PASSWORD="MYPASS"
@@ -0,0 +1,11 @@
menu "Example CoAP Server Configuration"
config EXAMPLE_COAP_PSK_KEY
string "Preshared Key (PSK) to used in the connection from the CoAP client"
depends on COAP_MBEDTLS_PSK
default "secret-key"
help
The Preshared Key to use to encrypt the communicatons. The same key must be
used at both ends of the CoAP connection, and the CoaP client must request
an URI prefixed with coaps:// instead of coap:// for DTLS to be used.
endmenu
@@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIID3DCCA0WgAwIBAgIJAMnlgL1czsmjMA0GCSqGSIb3DQEBCwUAMIGTMQswCQYD
VQQGEwJGUjEPMA0GA1UECAwGUmFkaXVzMRIwEAYDVQQHDAlTb21ld2hlcmUxFTAT
BgNVBAoMDEV4YW1wbGUgSW5jLjEgMB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBs
ZS5jb20xJjAkBgNVBAMMHUV4YW1wbGUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4X
DTE3MDYwNzA4MDY0OVoXDTI3MDYwNTA4MDY0OVowgZMxCzAJBgNVBAYTAkZSMQ8w
DQYDVQQIDAZSYWRpdXMxEjAQBgNVBAcMCVNvbWV3aGVyZTEVMBMGA1UECgwMRXhh
bXBsZSBJbmMuMSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxlLmNvbTEmMCQG
A1UEAwwdRXhhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwgZ8wDQYJKoZIhvcN
AQEBBQADgY0AMIGJAoGBALpWR23fn/TmHxsXsHdrydzPSd17fZkc71WsaicgQR66
1tIVYb22UWGfj9KPM8THMsV74ew4ZkaQ39qvU0iuQIRrKARFHFok+vbaecgWMeWe
vGIqdnmyB9gJYaFOKgtSkfXsu2ddsqdvLYwcDbczrq8X9yEXpN6mnxXeCcPG4F0p
AgMBAAGjggE0MIIBMDAdBgNVHQ4EFgQUgigpdAUpONoDq0pQ3yfxrslCSpcwgcgG
A1UdIwSBwDCBvYAUgigpdAUpONoDq0pQ3yfxrslCSpehgZmkgZYwgZMxCzAJBgNV
BAYTAkZSMQ8wDQYDVQQIDAZSYWRpdXMxEjAQBgNVBAcMCVNvbWV3aGVyZTEVMBMG
A1UECgwMRXhhbXBsZSBJbmMuMSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxl
LmNvbTEmMCQGA1UEAwwdRXhhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCCQDJ
5YC9XM7JozAMBgNVHRMEBTADAQH/MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly93
d3cuZXhhbXBsZS5jb20vZXhhbXBsZV9jYS5jcmwwDQYJKoZIhvcNAQELBQADgYEA
euxOBPInSJRKAIseMxPmAabtAqKNslZSmpG4He3lkKt+HM3jfznUt3psmD7j1hFW
S4l7KXzzajvaGYybDq5N9MqrDjhGn3VXZqOLMUNDL7OQq96TzgqsTBT1dmVSbNlt
PQgiAeKAk3tmH4lRRi9MTBSyJ6I92JYcS5H6Bs4ZwCc=
-----END CERTIFICATE-----
@@ -0,0 +1,70 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 47 (0x2f)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=FR, ST=Radius, L=Somewhere, O=Example Inc./emailAddress=admin@example.com, CN=Example Certificate Authority
Validity
Not Before: Jun 7 08:06:49 2017 GMT
Not After : Jun 5 08:06:49 2027 GMT
Subject: C=FR, ST=Radius, O=Example Inc., CN=Example Server Certificate/emailAddress=admin@example.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:c9:d8:e2:e0:75:91:83:87:d8:c8:80:c6:20:4d:
e9:14:24:30:98:33:53:fa:56:0e:ec:9a:43:7f:87:
a9:22:94:26:06:c7:ac:b5:d9:ec:55:06:81:b7:0d:
c9:24:51:49:fa:47:fb:4b:4e:fc:ed:75:8a:e1:28:
32:bc:c5:e0:4c:45:c4:58:60:15:67:1e:6b:40:19:
3f:f0:ab:92:61:92:2d:71:10:2e:f2:eb:bc:81:2f:
5a:3b:74:ca:5f:fd:e0:ee:d1:d9:07:6a:6c:20:c0:
07:88:b4:8b:0f:ad:1e:c9:4f:7c:11:98:37:89:15:
de:24:b1:11:1a:7c:97:4a:cf:f3:c8:cb:79:9e:9c:
c3:71:da:a6:94:97:f5:95:fd:61:06:44:e2:3f:12:
43:0b:1d:33:48:91:d2:ce:4f:97:a1:ed:6a:30:c7:
5d:98:b5:6e:0a:b7:4f:d9:03:ec:80:76:09:b0:40:
a1:a1:af:ab:2a:59:c4:0f:56:22:bc:be:14:be:18:
df:10:7d:5d:22:bf:e5:04:77:7a:75:6b:3e:eb:6d:
20:a1:a7:60:d4:f1:87:9d:9f:60:b9:d3:db:2c:25:
f4:91:4a:f1:d2:40:e5:a1:10:88:a0:41:5a:98:40:
ca:15:d7:e3:e6:3e:c0:6a:d5:46:b2:b4:90:b4:ae:
3b:e3
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Extended Key Usage:
TLS Web Server Authentication
X509v3 CRL Distribution Points:
Full Name:
URI:http://www.example.com/example_ca.crl
Signature Algorithm: sha1WithRSAEncryption
a4:25:21:51:0b:22:6c:63:8d:a9:c1:4f:04:33:69:79:34:f0:
36:dd:8f:6a:27:5f:07:a2:1d:ef:8b:f0:96:e6:e7:a3:b8:3b:
85:5e:3f:26:43:8a:8e:95:58:9c:a6:db:9c:51:bf:ea:53:16:
3e:c1:a8:11:1a:c6:cf:0e:a1:17:18:64:d2:05:f1:c0:9c:a6:
2b:16:c4:29:54:03:d2:17:bd:15:74:d6:ad:8a:8f:2d:cc:27:
3b:88:88:f2:ea:d0:a2:cb:e9:42:57:df:26:9f:8a:a2:02:2f:
35:b6:19:1d:26:43:44:af:12:4b:bc:b9:84:50:02:fd:1d:fa:
50:e8
-----BEGIN CERTIFICATE-----
MIIDWTCCAsKgAwIBAgIBLzANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UEBhMCRlIx
DzANBgNVBAgMBlJhZGl1czESMBAGA1UEBwwJU29tZXdoZXJlMRUwEwYDVQQKDAxF
eGFtcGxlIEluYy4xIDAeBgkqhkiG9w0BCQEWEWFkbWluQGV4YW1wbGUuY29tMSYw
JAYDVQQDDB1FeGFtcGxlIENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNzA2MDcw
ODA2NDlaFw0yNzA2MDUwODA2NDlaMHwxCzAJBgNVBAYTAkZSMQ8wDQYDVQQIDAZS
YWRpdXMxFTATBgNVBAoMDEV4YW1wbGUgSW5jLjEjMCEGA1UEAwwaRXhhbXBsZSBT
ZXJ2ZXIgQ2VydGlmaWNhdGUxIDAeBgkqhkiG9w0BCQEWEWFkbWluQGV4YW1wbGUu
Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAydji4HWRg4fYyIDG
IE3pFCQwmDNT+lYO7JpDf4epIpQmBsestdnsVQaBtw3JJFFJ+kf7S0787XWK4Sgy
vMXgTEXEWGAVZx5rQBk/8KuSYZItcRAu8uu8gS9aO3TKX/3g7tHZB2psIMAHiLSL
D60eyU98EZg3iRXeJLERGnyXSs/zyMt5npzDcdqmlJf1lf1hBkTiPxJDCx0zSJHS
zk+Xoe1qMMddmLVuCrdP2QPsgHYJsEChoa+rKlnED1YivL4UvhjfEH1dIr/lBHd6
dWs+620goadg1PGHnZ9gudPbLCX0kUrx0kDloRCIoEFamEDKFdfj5j7AatVGsrSQ
tK474wIDAQABo08wTTATBgNVHSUEDDAKBggrBgEFBQcDATA2BgNVHR8ELzAtMCug
KaAnhiVodHRwOi8vd3d3LmV4YW1wbGUuY29tL2V4YW1wbGVfY2EuY3JsMA0GCSqG
SIb3DQEBBQUAA4GBAKQlIVELImxjjanBTwQzaXk08Dbdj2onXweiHe+L8Jbm56O4
O4VePyZDio6VWJym25xRv+pTFj7BqBEaxs8OoRcYZNIF8cCcpisWxClUA9IXvRV0
1q2Kjy3MJzuIiPLq0KLL6UJX3yafiqICLzW2GR0mQ0SvEku8uYRQAv0d+lDo
-----END CERTIFICATE-----
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAydji4HWRg4fYyIDGIE3pFCQwmDNT+lYO7JpDf4epIpQmBses
tdnsVQaBtw3JJFFJ+kf7S0787XWK4SgyvMXgTEXEWGAVZx5rQBk/8KuSYZItcRAu
8uu8gS9aO3TKX/3g7tHZB2psIMAHiLSLD60eyU98EZg3iRXeJLERGnyXSs/zyMt5
npzDcdqmlJf1lf1hBkTiPxJDCx0zSJHSzk+Xoe1qMMddmLVuCrdP2QPsgHYJsECh
oa+rKlnED1YivL4UvhjfEH1dIr/lBHd6dWs+620goadg1PGHnZ9gudPbLCX0kUrx
0kDloRCIoEFamEDKFdfj5j7AatVGsrSQtK474wIDAQABAoIBAQC2kGDEPBJdMSW2
VCLfXRiPixwYzXQLXIMrJWwfkQg9qlmqkDd6U50aWkRA2UswegW7RhfYSZ0i+cmf
VMhvTVpOIlwwwtcY6b5/v1bBy60eaySGuuh79xQMlFO8qynQIMStvUfbGTqrdIRb
9VBB4YeS9T12fILejtTZwv2BQ2dj1Y1SCay6Ri85UzJqSClRKgHISybvVdLNjPvP
0TRFBr57zyjL6WE8teKiKchzQko2u86No5uBCdKGsrAkrsdcR0YqlM/pZxd3VKNm
+eny0k+dZZlvcPxzkzP4hEp9+Rw5rP9/s3s/cCwvuuC5JO32ATBWKCbTvPv/XPDb
MdSJtOshAoGBAPzk0eswkcbFYtpnpBNmBAr1dtAdW1lfjUI2ucMMwt7Wns0P/tt+
gq6Hi1wTaGP0l/dIECgeHwjtWj31ZJjQtFJ1y/kafxo4o9cA8vCydpdvSZaldAfg
sbLlDTDYzEpelaDIbNQBBXFoC5U9JlBhBsIFCL5Z8ZuIeFPsb7t5wwuHAoGBAMxT
jyWfNm1uNxp1xgCnrRsLPQPVnURrSFAqcHrECqRu3F7sozTN7q/cZViemxPvVDGQ
p9c+9bHwaYvW4trO5qDHJ++gGwm5L52bMAY1VUfeTt67fqrey43XpdmzcTX1V9Uj
QWawPUCSDzFjL1MjfCIejtyYf5ash53vj+T8r/vFAoGAA/OPVB1uKazr3n3AEo2F
gqZTNO1AgCT+EArK3EFWyiSQVqPpV4SihheYFdg3yVgJB9QYbIgL9BfBUTaEW97m
8mLkzP+c/Mvlw3ZAVYJ0V+llPPVY2saoACOUES9SAdd4fwqiqK1baGo3xB0wfBEI
CgAKIu9E1ylKuAT5ufQtGAECgYEAtP/kU5h5N3El4QupTdU7VDSdZTMqsHw0v8cI
gsf9AXKvRmtrnBA8u46KPHmruHoO5CVXeSZtsaXdaaH+rYQQ6yXg67WxnehtFLlv
TmCaXiLBTS9cYvMf8FOyuGnsBLeEietEOTov2G5KhR5uwsAxa2wUc7endor5S9/2
YQuyvV0CgYALbiFpILd5l1ip65eE6JdA3hfttUbV2j2NSW12ej69vqbeOfaSgNse
uYCcXFsBbQPhNPwA+4d1oCe8SyXZg1f7gE812z2Tyr/3vdVnNZlitoxhsHmGiyS7
gZdaTYCb78l9z0EBdaCVvA16owEle4SR6f9eCwzSI0WPOUra+x/hrA==
-----END RSA PRIVATE KEY-----
@@ -7,6 +7,13 @@
CONDITIONS OF ANY KIND, either express or implied.
*/
/*
* WARNING
* libcoap is not multi-thread safe, so only this thread must make any coap_*()
* calls. Any external (to this thread) data transmitted in/out via libcoap
* therefore has to be passed in/out by xQueue*() via this thread.
*/
#include <string.h>
#include <sys/socket.h>
@@ -22,14 +29,60 @@
#include "protocol_examples_common.h"
#if 1
/* Needed until coap_dtls.h becomes a part of libcoap proper */
#include "libcoap.h"
#include "coap_dtls.h"
#endif
#include "coap.h"
/* Set this to 9 to get verbose logging from within libcoap */
#define COAP_LOGGING_LEVEL 0
/* The examples use simple Pre-Shared-Key configuration that you can set via
'make menuconfig'.
If you'd rather not, just change the below entries to strings with
the config you want - ie #define EXAMPLE_COAP_PSK_KEY "some-agreed-preshared-key"
Note: PSK will only be used if the URI is prefixed with coaps://
instead of coap:// and the PSK must be one that the server supports
(potentially associated with the IDENTITY)
*/
#define EXAMPLE_COAP_PSK_KEY CONFIG_EXAMPLE_COAP_PSK_KEY
/* The examples use CoAP Logging Level that
you can set via 'make menuconfig'.
If you'd rather not, just change the below entry to a value
that is between 0 and 7 with
the config you want - ie #define EXAMPLE_COAP_LOG_DEFAULT_LEVEL 7
*/
#define EXAMPLE_COAP_LOG_DEFAULT_LEVEL CONFIG_COAP_LOG_DEFAULT_LEVEL
const static char *TAG = "CoAP_server";
static char espressif_data[100];
static int espressif_data_len = 0;
#ifdef CONFIG_COAP_MBEDTLS_PKI
/* CA cert, taken from coap_ca.pem
Server cert, taken from coap_server.crt
Server key, taken from coap_server.key
The PEM, CRT and KEY file are examples taken from the wpa2 enterprise
example.
To embed it in the app binary, the PEM, CRT and KEY file is named
in the component.mk COMPONENT_EMBED_TXTFILES variable.
*/
extern uint8_t ca_pem_start[] asm("_binary_coap_ca_pem_start");
extern uint8_t ca_pem_end[] asm("_binary_coap_ca_pem_end");
extern uint8_t server_crt_start[] asm("_binary_coap_server_crt_start");
extern uint8_t server_crt_end[] asm("_binary_coap_server_crt_end");
extern uint8_t server_key_start[] asm("_binary_coap_server_key_start");
extern uint8_t server_key_end[] asm("_binary_coap_server_key_end");
#endif /* CONFIG_COAP_MBEDTLS_PKI */
#define INITIAL_DATA "Hello World!"
/*
* The resource handler
*/
@@ -59,10 +112,9 @@ hnd_espressif_put(coap_context_t *ctx,
coap_resource_notify_observers(resource, NULL);
if (strcmp (espressif_data, "no data") == 0) {
if (strcmp (espressif_data, INITIAL_DATA) == 0) {
response->code = COAP_RESPONSE_CODE(201);
}
else {
} else {
response->code = COAP_RESPONSE_CODE(204);
}
@@ -70,7 +122,7 @@ hnd_espressif_put(coap_context_t *ctx,
(void)coap_get_data(request, &size, &data);
if (size == 0) { /* re-init */
snprintf(espressif_data, sizeof(espressif_data), "no data");
snprintf(espressif_data, sizeof(espressif_data), INITIAL_DATA);
espressif_data_len = strlen(espressif_data);
} else {
espressif_data_len = size > sizeof (espressif_data) ? sizeof (espressif_data) : size;
@@ -88,23 +140,41 @@ hnd_espressif_delete(coap_context_t *ctx,
coap_pdu_t *response)
{
coap_resource_notify_observers(resource, NULL);
snprintf(espressif_data, sizeof(espressif_data), "no data");
snprintf(espressif_data, sizeof(espressif_data), INITIAL_DATA);
espressif_data_len = strlen(espressif_data);
response->code = COAP_RESPONSE_CODE(202);
}
static void coap_example_thread(void *p)
#ifdef CONFIG_COAP_MBEDTLS_PKI
static int
verify_cn_callback(const char *cn,
const uint8_t *asn1_public_cert,
size_t asn1_length,
coap_session_t *session,
unsigned depth,
int validated,
void *arg
)
{
coap_log(LOG_INFO, "CN '%s' presented by server (%s)\n",
cn, depth ? "CA" : "Certificate");
return 1;
}
#endif /* CONFIG_COAP_MBEDTLS_PKI */
static void coap_example_server(void *p)
{
coap_context_t *ctx = NULL;
coap_address_t serv_addr;
coap_address_t serv_addr;
coap_resource_t *resource = NULL;
snprintf(espressif_data, sizeof(espressif_data), "no data");
snprintf(espressif_data, sizeof(espressif_data), INITIAL_DATA);
espressif_data_len = strlen(espressif_data);
coap_set_log_level(COAP_LOGGING_LEVEL);
coap_set_log_level(EXAMPLE_COAP_LOG_DEFAULT_LEVEL);
while (1) {
coap_endpoint_t *ep_udp = NULL;
coap_endpoint_t *ep_tcp = NULL;
coap_endpoint_t *ep = NULL;
unsigned wait_ms;
/* Prepare the CoAP server socket */
@@ -115,19 +185,93 @@ static void coap_example_thread(void *p)
ctx = coap_new_context(NULL);
if (!ctx) {
continue;
ESP_LOGE(TAG, "coap_new_context() failed");
continue;
}
ep_udp = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_UDP);
if (!ep_udp) {
goto clean_up;
#ifdef CONFIG_COAP_MBEDTLS_PSK
/* Need PSK setup before we set up endpoints */
coap_context_set_psk(ctx, "CoAP",
(const uint8_t *)EXAMPLE_COAP_PSK_KEY,
sizeof(EXAMPLE_COAP_PSK_KEY) - 1);
#endif /* CONFIG_COAP_MBEDTLS_PSK */
#ifdef CONFIG_COAP_MBEDTLS_PKI
unsigned int ca_pem_bytes = ca_pem_end - ca_pem_start;
unsigned int server_crt_bytes = server_crt_end - server_crt_start;
unsigned int server_key_bytes = server_key_end - server_key_start;
coap_dtls_pki_t dtls_pki;
memset (&dtls_pki, 0, sizeof(dtls_pki));
dtls_pki.version = COAP_DTLS_PKI_SETUP_VERSION;
if (ca_pem_bytes) {
/*
* Add in additional certificate checking.
* This list of enabled can be tuned for the specific
* requirements - see 'man coap_encryption'.
*
* Note: A list of root ca file can be setup separately using
* coap_context_set_pki_root_cas(), but the below is used to
* define what checking actually takes place.
*/
dtls_pki.verify_peer_cert = 1;
dtls_pki.require_peer_cert = 1;
dtls_pki.allow_self_signed = 1;
dtls_pki.allow_expired_certs = 1;
dtls_pki.cert_chain_validation = 1;
dtls_pki.cert_chain_verify_depth = 2;
dtls_pki.check_cert_revocation = 1;
dtls_pki.allow_no_crl = 1;
dtls_pki.allow_expired_crl = 1;
dtls_pki.allow_bad_md_hash = 1;
dtls_pki.allow_short_rsa_length = 1;
dtls_pki.validate_cn_call_back = verify_cn_callback;
dtls_pki.cn_call_back_arg = NULL;
dtls_pki.validate_sni_call_back = NULL;
dtls_pki.sni_call_back_arg = NULL;
}
ep_tcp = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_TCP);
if (!ep_tcp) {
goto clean_up;
dtls_pki.pki_key.key_type = COAP_PKI_KEY_PEM_BUF;
dtls_pki.pki_key.key.pem_buf.public_cert = server_crt_start;
dtls_pki.pki_key.key.pem_buf.public_cert_len = server_crt_bytes;
dtls_pki.pki_key.key.pem_buf.private_key = server_key_start;
dtls_pki.pki_key.key.pem_buf.private_key_len = server_key_bytes;
dtls_pki.pki_key.key.pem_buf.ca_cert = ca_pem_start;
dtls_pki.pki_key.key.pem_buf.ca_cert_len = ca_pem_bytes;
coap_context_set_pki(ctx, &dtls_pki);
#endif /* CONFIG_COAP_MBEDTLS_PKI */
ep = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_UDP);
if (!ep) {
ESP_LOGE(TAG, "udp: coap_new_endpoint() failed");
goto clean_up;
}
ep = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_TCP);
if (!ep) {
ESP_LOGE(TAG, "tcp: coap_new_endpoint() failed");
goto clean_up;
}
#if defined(CONFIG_COAP_MBEDTLS_PSK) || defined(CONFIG_COAP_MBEDTLS_PKI)
if (coap_dtls_is_supported()) {
#ifndef CONFIG_MBEDTLS_TLS_SERVER
/* This is not critical as unencrypted support is still available */
ESP_LOGI(TAG, "MbedTLS (D)TLS Server Mode not configured");
#else /* CONFIG_MBEDTLS_TLS_SERVER */
serv_addr.addr.sin.sin_port = htons(COAPS_DEFAULT_PORT);
ep = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_DTLS);
if (!ep) {
ESP_LOGE(TAG, "dtls: coap_new_endpoint() failed");
goto clean_up;
}
#endif /* CONFIG_MBEDTLS_TLS_SERVER */
} else {
/* This is not critical as unencrypted support is still available */
ESP_LOGI(TAG, "MbedTLS (D)TLS Server Mode not configured");
}
#endif /* CONFIG_COAP_MBEDTLS_PSK CONFIG_COAP_MBEDTLS_PKI */
resource = coap_resource_init(coap_make_str_const("Espressif"), 0);
if (!resource) {
goto clean_up;
ESP_LOGE(TAG, "coap_resource_init() failed");
goto clean_up;
}
coap_register_handler(resource, COAP_REQUEST_GET, hnd_espressif_get);
coap_register_handler(resource, COAP_REQUEST_PUT, hnd_espressif_put);
@@ -162,7 +306,7 @@ clean_up:
void app_main(void)
{
ESP_ERROR_CHECK( nvs_flash_init() );
tcpip_adapter_init();
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
@@ -171,5 +315,5 @@ void app_main(void)
*/
ESP_ERROR_CHECK(example_connect());
xTaskCreate(coap_example_thread, "coap", 1024 * 5, NULL, 5, NULL);
xTaskCreate(coap_example_server, "coap", 8 * 1024, NULL, 5, NULL);
}
+4 -8
View File
@@ -7,20 +7,16 @@
; Please visit documentation for the other options and examples
; http://docs.platformio.org/page/projectconf.html
[env:esp32dev]
[env]
platform = espressif32
framework = espidf
board = esp32dev
monitor_speed = 115200
[env:esp32dev]
board = esp32dev
[env:esp-wrover-kit]
platform = espressif32
framework = espidf
board = esp-wrover-kit
monitor_speed = 115200
[env:lolin32]
platform = espressif32
framework = espidf
board = lolin32
monitor_speed = 115200
+4 -8
View File
@@ -7,20 +7,16 @@
; Please visit documentation for the other options and examples
; http://docs.platformio.org/page/projectconf.html
[env:esp32dev]
[env]
platform = espressif32
framework = espidf
board = esp32dev
monitor_speed = 115200
[env:esp32dev]
board = esp32dev
[env:esp-wrover-kit]
platform = espressif32
framework = espidf
board = esp-wrover-kit
monitor_speed = 115200
[env:lolin32]
platform = espressif32
framework = espidf
board = lolin32
monitor_speed = 115200
+7 -11
View File
@@ -7,23 +7,19 @@
; Please visit documentation for the other options and examples
; http://docs.platformio.org/page/projectconf.html
[env:nano32]
[env]
platform = espressif32
framework = espidf
board = nano32
build_flags = -DCONFIG_WIFI_SSID=\"ESP_AP\" -DCONFIG_WIFI_PASSWORD=\"MYPASS\"
monitor_speed = 115200
[env:esp32dev]
board = esp32dev
[env:nano32]
board = nano32
[env:espea32]
platform = espressif32
framework = espidf
board = espea32
build_flags = -DCONFIG_WIFI_SSID=\"ESP_AP\" -DCONFIG_WIFI_PASSWORD=\"MYPASS\"
monitor_speed = 115200
[env:esp320]
platform = espressif32
framework = espidf
board = esp320
build_flags = -DCONFIG_WIFI_SSID=\"ESP_AP\" -DCONFIG_WIFI_PASSWORD=\"MYPASS\"
monitor_speed = 115200
@@ -0,0 +1,2 @@
CONFIG_EXAMPLE_WIFI_SSID="MYSSID"
CONFIG_EXAMPLE_WIFI_PASSWORD="MYPASS"
@@ -24,13 +24,13 @@
/* Constants that aren't configurable in menuconfig */
#define WEB_SERVER "example.com"
#define WEB_PORT 80
#define WEB_URL "http://example.com/"
#define WEB_PORT "80"
#define WEB_PATH "/"
static const char *TAG = "example";
static const char *REQUEST = "GET " WEB_URL " HTTP/1.0\r\n"
"Host: "WEB_SERVER"\r\n"
static const char *REQUEST = "GET " WEB_PATH " HTTP/1.0\r\n"
"Host: "WEB_SERVER":"WEB_PORT"\r\n"
"User-Agent: esp-idf/1.0 esp32\r\n"
"\r\n";
@@ -46,7 +46,7 @@ static void http_get_task(void *pvParameters)
char recv_buf[64];
while(1) {
int err = getaddrinfo(WEB_SERVER, "80", &hints, &res);
int err = getaddrinfo(WEB_SERVER, WEB_PORT, &hints, &res);
if(err != 0 || res == NULL) {
ESP_LOGE(TAG, "DNS lookup failed err=%d res=%p", err, res);
@@ -119,10 +119,10 @@ static void http_get_task(void *pvParameters)
}
}
void app_main()
void app_main(void)
{
ESP_ERROR_CHECK( nvs_flash_init() );
tcpip_adapter_init();
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
@@ -7,23 +7,16 @@
; Please visit documentation for the other options and examples
; http://docs.platformio.org/page/projectconf.html
[env:nano32]
[env]
platform = espressif32
framework = espidf
board = nano32
build_flags = -DCONFIG_WIFI_SSID=\"ESP_AP\" -DCONFIG_WIFI_PASSWORD=\"MYPASS\"
monitor_speed = 115200
[env:espea32]
platform = espressif32
framework = espidf
board = espea32
build_flags = -DCONFIG_WIFI_SSID=\"ESP_AP\" -DCONFIG_WIFI_PASSWORD=\"MYPASS\"
monitor_speed = 115200
[env:pocket_32]
board = pocket_32
[env:esp32dev]
platform = espressif32
framework = espidf
board = esp32dev
build_flags = -DCONFIG_WIFI_SSID=\"ESP_AP\" -DCONFIG_WIFI_PASSWORD=\"MYPASS\"
monitor_speed = 115200
[env:odroid_esp32]
board = odroid_esp32
[env:featheresp32]
board = featheresp32
@@ -31,7 +31,7 @@
#define BUF_SIZE (1024)
static void echo_task()
static void echo_task(void *arg)
{
/* Configure parameters of an UART driver,
* communication pins and install the driver */
@@ -40,11 +40,12 @@ static void echo_task()
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_APB,
};
uart_driver_install(UART_NUM_1, BUF_SIZE * 2, 0, 0, NULL, 0);
uart_param_config(UART_NUM_1, &uart_config);
uart_set_pin(UART_NUM_1, ECHO_TEST_TXD, ECHO_TEST_RXD, ECHO_TEST_RTS, ECHO_TEST_CTS);
uart_driver_install(UART_NUM_1, BUF_SIZE * 2, 0, 0, NULL, 0);
// Configure a temporary buffer for the incoming data
uint8_t *data = (uint8_t *) malloc(BUF_SIZE);
@@ -57,7 +58,7 @@ static void echo_task()
}
}
void app_main()
void app_main(void)
{
xTaskCreate(echo_task, "uart_echo_task", 1024, NULL, 10, NULL);
}
+8 -15
View File
@@ -7,23 +7,16 @@
; Please visit documentation for the other options and examples
; http://docs.platformio.org/page/projectconf.html
[env:nano32]
[env]
platform = espressif32
framework = espidf
board = nano32
build_flags = -DCONFIG_WIFI_SSID=\"ESP_AP\" -DCONFIG_WIFI_PASSWORD=\"MYPASS\"
monitor_speed = 115200
[env:espea32]
platform = espressif32
framework = espidf
board = espea32
build_flags = -DCONFIG_WIFI_SSID=\"ESP_AP\" -DCONFIG_WIFI_PASSWORD=\"MYPASS\"
monitor_speed = 115200
[env:esp32thing]
board = esp32thing
[env:esp32dev]
platform = espressif32
framework = espidf
board = esp32dev
build_flags = -DCONFIG_WIFI_SSID=\"ESP_AP\" -DCONFIG_WIFI_PASSWORD=\"MYPASS\"
monitor_speed = 115200
[env:esp32-gateway]
board = esp32-gateway
[env:heltec_wifi_kit_32]
board = heltec_wifi_kit_32
-1
View File
@@ -14,4 +14,3 @@ src_dir = main
platform = espressif32
framework = espidf
board = esp32dev
build_flags = -DCONFIG_WIFI_SSID=\"ESP_AP\" -DCONFIG_WIFI_PASSWORD=\"MYPASS\"
@@ -6,3 +6,4 @@ CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y
CONFIG_BOOTLOADER_LOG_LEVEL=2
CONFIG_LOG_DEFAULT_LEVEL_WARN=y
CONFIG_LOG_DEFAULT_LEVEL=2
CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP=y
-1
View File
@@ -11,4 +11,3 @@
platform = espressif32
framework = espidf
board = esp32dev
build_flags = -DCONFIG_WIFI_SSID=\"ESP_AP\" -DCONFIG_WIFI_PASSWORD=\"MYPASS\"
@@ -6,3 +6,4 @@ CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y
CONFIG_BOOTLOADER_LOG_LEVEL=2
CONFIG_LOG_DEFAULT_LEVEL_WARN=y
CONFIG_LOG_DEFAULT_LEVEL=2
CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP=y
+5 -7
View File
@@ -1,8 +1,6 @@
idf_component_register(SRCS "ulp_example_main.c")
# idf_component_register(SRCS "ulp_example_main.c"
# INCLUDE_DIRS ""
# REQUIRES soc nvs_flash ulp)
idf_component_register(SRCS "ulp_example_main.c"
INCLUDE_DIRS ""
REQUIRES soc nvs_flash ulp)
#
# ULP support additions to component CMakeLists.txt.
#
@@ -12,7 +10,7 @@ set(ulp_app_name ulp_main)
# 2. Specify all assembly source files.
# Files should be placed into a separate directory (in this case, ulp/),
# which should not be added to COMPONENT_SRCS.
set(ulp_s_sources "../ulp/pulse_cnt.S")
set(ulp_s_sources "../ulp/pulse_cnt.S" "../ulp/wake_up.S")
#
# 3. List all the component source files which include automatically
# generated ULP export file, ${ulp_app_name}.h:
@@ -20,4 +18,4 @@ set(ulp_exp_dep_srcs "ulp_example_main.c")
#
# 4. Call function to build ULP binary and embed in project using the argument
# values above.
ulp_embed_binary(${ulp_app_name} ${ulp_s_sources} ${ulp_exp_dep_srcs})
ulp_embed_binary(${ulp_app_name} "${ulp_s_sources}" "${ulp_exp_dep_srcs}")
@@ -22,10 +22,10 @@
extern const uint8_t ulp_main_bin_start[] asm("_binary_ulp_main_bin_start");
extern const uint8_t ulp_main_bin_end[] asm("_binary_ulp_main_bin_end");
static void init_ulp_program();
static void update_pulse_count();
static void init_ulp_program(void);
static void update_pulse_count(void);
void app_main()
void app_main(void)
{
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
if (cause != ESP_SLEEP_WAKEUP_ULP) {
@@ -41,7 +41,7 @@ void app_main()
esp_deep_sleep_start();
}
static void init_ulp_program()
static void init_ulp_program(void)
{
esp_err_t err = ulp_load_binary(0, ulp_main_bin_start,
(ulp_main_bin_end - ulp_main_bin_start) / sizeof(uint32_t));
@@ -49,7 +49,8 @@ static void init_ulp_program()
/* GPIO used for pulse counting. */
gpio_num_t gpio_num = GPIO_NUM_0;
assert(rtc_gpio_desc[gpio_num].reg && "GPIO used for pulse counting must be an RTC IO");
int rtcio_num = rtc_io_number_get(gpio_num);
assert(rtc_gpio_is_valid_gpio(gpio_num) && "GPIO used for pulse counting must be an RTC IO");
/* Initialize some variables used by ULP program.
* Each 'ulp_xyz' variable corresponds to 'xyz' variable in the ULP program.
@@ -63,7 +64,7 @@ static void init_ulp_program()
ulp_debounce_counter = 3;
ulp_debounce_max_count = 3;
ulp_next_edge = 0;
ulp_io_number = rtc_gpio_desc[gpio_num].rtc_num; /* map from GPIO# to RTC_IO# */
ulp_io_number = rtcio_num; /* map from GPIO# to RTC_IO# */
ulp_edge_count_to_wake_up = 10;
/* Initialize selected GPIO as RTC IO, enable input, disable pullup and pulldown */
@@ -91,7 +92,7 @@ static void init_ulp_program()
ESP_ERROR_CHECK(err);
}
static void update_pulse_count()
static void update_pulse_count(void)
{
const char* namespace = "plusecnt";
const char* count_key = "count";
-11
View File
@@ -144,14 +144,3 @@ edge_detected:
jump wake_up, eq
/* Not yet. End program */
halt
.global wake_up
wake_up:
/* Check if the system can be woken up */
READ_RTC_FIELD(RTC_CNTL_LOW_POWER_ST_REG, RTC_CNTL_RDY_FOR_WAKEUP)
and r0, r0, 1
jump wake_up, eq
/* Wake up the SoC, end program */
wake
halt
+16
View File
@@ -0,0 +1,16 @@
/* ULP assembly files are passed through C preprocessor first, so include directives
and C macros may be used in these files
*/
#include "soc/rtc_cntl_reg.h"
#include "soc/soc_ulp.h"
.global wake_up
wake_up:
/* Check if the system can be woken up */
READ_RTC_FIELD(RTC_CNTL_LOW_POWER_ST_REG, RTC_CNTL_RDY_FOR_WAKEUP)
and r0, r0, 1
jump wake_up, eq
/* Wake up the SoC, end program */
wake
halt