Merge branch 'master' into feature/btdm_avrc
This commit is contained in:
commit
007efdb852
62 changed files with 34390 additions and 112 deletions
10
.gitignore
vendored
10
.gitignore
vendored
|
@ -19,9 +19,9 @@ GPATH
|
||||||
.settings
|
.settings
|
||||||
|
|
||||||
# Example project files
|
# Example project files
|
||||||
examples/*/*/sdkconfig
|
examples/**/sdkconfig
|
||||||
examples/*/*/sdkconfig.old
|
examples/**/sdkconfig.old
|
||||||
examples/*/*/build
|
examples/**/build
|
||||||
|
|
||||||
#Doc build artifacts
|
#Doc build artifacts
|
||||||
docs/_build/
|
docs/_build/
|
||||||
|
@ -33,3 +33,7 @@ docs/man/
|
||||||
tools/unit-test-app/sdkconfig
|
tools/unit-test-app/sdkconfig
|
||||||
tools/unit-test-app/sdkconfig.old
|
tools/unit-test-app/sdkconfig.old
|
||||||
tools/unit-test-app/build
|
tools/unit-test-app/build
|
||||||
|
|
||||||
|
# AWS IoT Examples require device-specific certs/keys
|
||||||
|
examples/protocols/aws_iot/*/main/certs/*.pem.*
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ build_template_app:
|
||||||
IDF_PATH: "$CI_PROJECT_DIR"
|
IDF_PATH: "$CI_PROJECT_DIR"
|
||||||
GIT_STRATEGY: clone
|
GIT_STRATEGY: clone
|
||||||
BATCH_BUILD: "1"
|
BATCH_BUILD: "1"
|
||||||
|
IDF_CI_BUILD: "1"
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- git clone https://github.com/espressif/esp-idf-template.git
|
- git clone https://github.com/espressif/esp-idf-template.git
|
||||||
|
@ -224,6 +225,7 @@ push_master_to_github:
|
||||||
image: espressif/esp32-ci-env
|
image: espressif/esp32-ci-env
|
||||||
variables:
|
variables:
|
||||||
GIT_STRATEGY: clone
|
GIT_STRATEGY: clone
|
||||||
|
GITHUB_PUSH_REFS: refs/remotes/origin/release refs/remotes/origin/master
|
||||||
script:
|
script:
|
||||||
- mkdir -p ~/.ssh
|
- mkdir -p ~/.ssh
|
||||||
- chmod 700 ~/.ssh
|
- chmod 700 ~/.ssh
|
||||||
|
@ -232,7 +234,14 @@ push_master_to_github:
|
||||||
- chmod 600 ~/.ssh/id_rsa
|
- chmod 600 ~/.ssh/id_rsa
|
||||||
- echo -e "Host github.com\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
|
- echo -e "Host github.com\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
|
||||||
- git remote add github git@github.com:espressif/esp-idf.git
|
- git remote add github git@github.com:espressif/esp-idf.git
|
||||||
- git push --follow-tags github HEAD
|
# What the next line of script does: goes through the list of refs for all branches we push to github,
|
||||||
|
# generates a snippet of shell which is evaluated. The snippet checks CI_BUILD_REF against the SHA
|
||||||
|
# (aka objectname) at tip of each branch, and if any SHAs match then it checks out the local branch
|
||||||
|
# and then pushes that ref to a corresponding github branch
|
||||||
|
#
|
||||||
|
# NB: In gitlab 9.x, CI_BUILD_REF was deprecated. New name is CI_COMMIT_REF. If below command suddenly
|
||||||
|
# generates bash syntax errors, this is probably why.
|
||||||
|
- eval $(git for-each-ref --shell bash --format 'if [ $CI_BUILD_REF == %(objectname) ]; then git checkout -B %(refname:strip=3); git push --follow-tags github %(refname:strip=3); fi;' $GITHUB_PUSH_REFS)
|
||||||
|
|
||||||
|
|
||||||
deploy_docs:
|
deploy_docs:
|
||||||
|
|
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -13,3 +13,6 @@
|
||||||
[submodule "components/coap/libcoap"]
|
[submodule "components/coap/libcoap"]
|
||||||
path = components/coap/libcoap
|
path = components/coap/libcoap
|
||||||
url = https://github.com/obgm/libcoap.git
|
url = https://github.com/obgm/libcoap.git
|
||||||
|
[submodule "components/aws_iot/aws-iot-device-sdk-embedded-C"]
|
||||||
|
path = components/aws_iot/aws-iot-device-sdk-embedded-C
|
||||||
|
url = https://github.com/espressif/aws-iot-device-sdk-embedded-C.git
|
||||||
|
|
|
@ -52,9 +52,9 @@ You don't need to run `make all` before running `make flash`, `make flash` will
|
||||||
|
|
||||||
## Viewing Serial Output
|
## Viewing Serial Output
|
||||||
|
|
||||||
The `make monitor` target will use the already-installed [miniterm](http://pyserial.readthedocs.io/en/latest/tools.html#module-serial.tools.miniterm) (a part of pyserial) to display serial output from the ESP32 on the terminal console.
|
The `make monitor` target uses the [idf_monitor tool](http://esp-idf.readthedocs.io/en/latest/idf-monitor.html) to display serial output from the ESP32. idf_monitor also has a range of features to decode crash output and interact with the device. [Check the documentation page for details](http://esp-idf.readthedocs.io/en/latest/idf-monitor.html).
|
||||||
|
|
||||||
Exit miniterm by typing Ctrl-].
|
Exit the monitor by typing Ctrl-].
|
||||||
|
|
||||||
To flash and monitor output in one pass, you can run:
|
To flash and monitor output in one pass, you can run:
|
||||||
|
|
||||||
|
|
32
components/aws_iot/Kconfig
Normal file
32
components/aws_iot/Kconfig
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
menuconfig AWS_IOT_SDK
|
||||||
|
bool "Amazon Web Services IoT Platform"
|
||||||
|
help
|
||||||
|
Select this option to enable support for the AWS IoT platform,
|
||||||
|
via the esp-idf component for the AWS IoT Device C SDK.
|
||||||
|
|
||||||
|
config AWS_IOT_MQTT_HOST
|
||||||
|
string "AWS IoT Endpoint Hostname"
|
||||||
|
depends on AWS_IOT_SDK
|
||||||
|
default ""
|
||||||
|
help
|
||||||
|
Default endpoint host name to connect to AWS IoT MQTT/S gateway
|
||||||
|
|
||||||
|
This is the custom endpoint hostname and is specific to an AWS
|
||||||
|
IoT account. You can find it by logging into your AWS IoT
|
||||||
|
Console and clicking the Settings button. The endpoint hostname
|
||||||
|
is shown under the "Custom Endpoint" heading on this page.
|
||||||
|
|
||||||
|
If you need per-device hostnames for different regions or
|
||||||
|
accounts, you can override the default hostname in your app.
|
||||||
|
|
||||||
|
config AWS_IOT_MQTT_PORT
|
||||||
|
int "AWS IoT MQTT Port"
|
||||||
|
depends on AWS_IOT_SDK
|
||||||
|
default 8883
|
||||||
|
range 0 65535
|
||||||
|
help
|
||||||
|
Default port number to connect to AWS IoT MQTT/S gateway
|
||||||
|
|
||||||
|
If you need per-device port numbers for different regions, you can
|
||||||
|
override the default port number in your app.
|
||||||
|
|
1
components/aws_iot/aws-iot-device-sdk-embedded-C
Submodule
1
components/aws_iot/aws-iot-device-sdk-embedded-C
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 7132505b00d2dd57f48478e75efa636021919aae
|
20
components/aws_iot/component.mk
Normal file
20
components/aws_iot/component.mk
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#
|
||||||
|
# Component Makefile
|
||||||
|
#
|
||||||
|
|
||||||
|
ifdef CONFIG_AWS_IOT_SDK
|
||||||
|
|
||||||
|
COMPONENT_ADD_INCLUDEDIRS := include aws-iot-device-sdk-embedded-C/include
|
||||||
|
|
||||||
|
COMPONENT_SRCDIRS := aws-iot-device-sdk-embedded-C/src port
|
||||||
|
|
||||||
|
# Check the submodule is initialised
|
||||||
|
COMPONENT_SUBMODULES := aws-iot-device-sdk-embedded-C
|
||||||
|
|
||||||
|
|
||||||
|
else
|
||||||
|
# Disable AWS IoT support
|
||||||
|
COMPONENT_ADD_INCLUDEDIRS :=
|
||||||
|
COMPONENT_ADD_LDFLAGS :=
|
||||||
|
COMPONENT_SRCDIRS :=
|
||||||
|
endif
|
60
components/aws_iot/include/aws_iot_config.h
Normal file
60
components/aws_iot/include/aws_iot_config.h
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
* A copy of the License is located at
|
||||||
|
*
|
||||||
|
* http://aws.amazon.com/apache2.0
|
||||||
|
*
|
||||||
|
* or in the "license" file accompanying this file. This file is distributed
|
||||||
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||||
|
* express or implied. See the License for the specific language governing
|
||||||
|
* permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file aws_iot_config.h
|
||||||
|
* @brief AWS IoT specific configuration file
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _AWS_IOT_CONFIG_H_
|
||||||
|
#define _AWS_IOT_CONFIG_H_
|
||||||
|
|
||||||
|
#include "aws_iot_log.h"
|
||||||
|
|
||||||
|
// This configuration macro needs to be available globally to enable threading
|
||||||
|
#define _ENABLE_THREAD_SUPPORT_
|
||||||
|
|
||||||
|
// These values are defined in the menuconfig of the AWS IoT component.
|
||||||
|
// However, you can override these constants from your own code.
|
||||||
|
#define AWS_IOT_MQTT_HOST CONFIG_AWS_IOT_MQTT_HOST ///< Customer specific MQTT HOST. The same will be used for Thing Shadow
|
||||||
|
#define AWS_IOT_MQTT_PORT CONFIG_AWS_IOT_MQTT_PORT ///< default port for MQTT/S
|
||||||
|
|
||||||
|
// These values are defaults and are used for ShadowConnectParametersDefault.
|
||||||
|
// You should override them from your own code.
|
||||||
|
#define AWS_IOT_MQTT_CLIENT_ID "ESP32" ///< MQTT client ID should be unique for every device
|
||||||
|
#define AWS_IOT_MY_THING_NAME "ESP32" ///< Thing Name of the Shadow this device is associated with
|
||||||
|
|
||||||
|
// MQTT PubSub
|
||||||
|
#define AWS_IOT_MQTT_TX_BUF_LEN 512 ///< Any time a message is sent out through the MQTT layer. The message is copied into this buffer anytime a publish is done. This will also be used in the case of Thing Shadow
|
||||||
|
#define AWS_IOT_MQTT_RX_BUF_LEN 512 ///< Any message that comes into the device should be less than this buffer size. If a received message is bigger than this buffer size the message will be dropped.
|
||||||
|
#define AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS 5 ///< Maximum number of topic filters the MQTT client can handle at any given time. This should be increased appropriately when using Thing Shadow
|
||||||
|
|
||||||
|
// Thing Shadow specific configs
|
||||||
|
#define SHADOW_MAX_SIZE_OF_RX_BUFFER (AWS_IOT_MQTT_RX_BUF_LEN + 1) ///< Maximum size of the SHADOW buffer to store the received Shadow message
|
||||||
|
#define MAX_SIZE_OF_UNIQUE_CLIENT_ID_BYTES 80 ///< Maximum size of the Unique Client Id. For More info on the Client Id refer \ref response "Acknowledgments"
|
||||||
|
#define MAX_SIZE_CLIENT_ID_WITH_SEQUENCE (MAX_SIZE_OF_UNIQUE_CLIENT_ID_BYTES + 10) ///< This is size of the extra sequence number that will be appended to the Unique client Id
|
||||||
|
#define MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE (MAX_SIZE_CLIENT_ID_WITH_SEQUENCE + 20) ///< This is size of the the total clientToken key and value pair in the JSON
|
||||||
|
#define MAX_ACKS_TO_COMEIN_AT_ANY_GIVEN_TIME 10 ///< At Any given time we will wait for this many responses. This will correlate to the rate at which the shadow actions are requested
|
||||||
|
#define MAX_THINGNAME_HANDLED_AT_ANY_GIVEN_TIME 10 ///< We could perform shadow action on any thing Name and this is maximum Thing Names we can act on at any given time
|
||||||
|
#define MAX_JSON_TOKEN_EXPECTED 120 ///< These are the max tokens that is expected to be in the Shadow JSON document. Include the metadata that gets published
|
||||||
|
#define MAX_SHADOW_TOPIC_LENGTH_WITHOUT_THINGNAME 60 ///< All shadow actions have to be published or subscribed to a topic which is of the formablogt $aws/things/{thingName}/shadow/update/accepted. This refers to the size of the topic without the Thing Name
|
||||||
|
#define MAX_SIZE_OF_THING_NAME 20 ///< The Thing Name should not be bigger than this value. Modify this if the Thing Name needs to be bigger
|
||||||
|
#define MAX_SHADOW_TOPIC_LENGTH_BYTES (MAX_SHADOW_TOPIC_LENGTH_WITHOUT_THINGNAME + MAX_SIZE_OF_THING_NAME) ///< This size includes the length of topic with Thing Name
|
||||||
|
|
||||||
|
// Auto Reconnect specific config
|
||||||
|
#define AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL 1000 ///< Minimum time before the First reconnect attempt is made as part of the exponential back-off algorithm
|
||||||
|
#define AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL 128000 ///< Maximum time interval after which exponential back-off will stop attempting to reconnect.
|
||||||
|
|
||||||
|
#endif /* _AWS_IOT_CONFIG_H_ */
|
44
components/aws_iot/include/aws_iot_log.h
Normal file
44
components/aws_iot/include/aws_iot_log.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
/* (these two headers aren't used here, but AWS IoT SDK code relies on them
|
||||||
|
being included from here...) */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "esp_log.h"
|
||||||
|
|
||||||
|
/* This is a stub replacement for the aws_iot_log.h header in the AWS IoT SDK,
|
||||||
|
which redirects their logging framework into the esp-idf logging framework.
|
||||||
|
|
||||||
|
The current (2.1.1) upstream AWS IoT SDK doesn't allow this as some of its
|
||||||
|
headers include aws_iot_log.h, but our modified fork does.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// redefine the AWS IoT log functions to call into the IDF log layer
|
||||||
|
#define IOT_DEBUG(format, ...) ESP_LOGD("aws_iot", format, ##__VA_ARGS__)
|
||||||
|
#define IOT_INFO(format, ...) ESP_LOGI("aws_iot", format, ##__VA_ARGS__)
|
||||||
|
#define IOT_WARN(format, ...) ESP_LOGW("aws_iot", format, ##__VA_ARGS__)
|
||||||
|
#define IOT_ERROR(format, ...) ESP_LOGE("aws_iot", format, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
/* Function tracing macros used in AWS IoT SDK,
|
||||||
|
mapped to "verbose" level output
|
||||||
|
*/
|
||||||
|
#define FUNC_ENTRY ESP_LOGV("aws_iot", "FUNC_ENTRY: %s L#%d \n", __func__, __LINE__)
|
||||||
|
#define FUNC_EXIT_RC(x) \
|
||||||
|
do { \
|
||||||
|
ESP_LOGV("aws_iot", "FUNC_EXIT: %s L#%d Return Code : %d \n", __func__, __LINE__, x); \
|
||||||
|
return x; \
|
||||||
|
} while(0)
|
64
components/aws_iot/include/network_platform.h
Normal file
64
components/aws_iot/include/network_platform.h
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Additions Copyright 2016 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
* A copy of the License is located at
|
||||||
|
*
|
||||||
|
* http://aws.amazon.com/apache2.0
|
||||||
|
*
|
||||||
|
* or in the "license" file accompanying this file. This file is distributed
|
||||||
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||||
|
* express or implied. See the License for the specific language governing
|
||||||
|
* permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IOTSDKC_NETWORK_MBEDTLS_PLATFORM_H_H
|
||||||
|
|
||||||
|
#if !defined(MBEDTLS_CONFIG_FILE)
|
||||||
|
#include "mbedtls/config.h"
|
||||||
|
#else
|
||||||
|
#include MBEDTLS_CONFIG_FILE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "mbedtls/platform.h"
|
||||||
|
#include "mbedtls/net.h"
|
||||||
|
#include "mbedtls/ssl.h"
|
||||||
|
#include "mbedtls/entropy.h"
|
||||||
|
#include "mbedtls/ctr_drbg.h"
|
||||||
|
#include "mbedtls/certs.h"
|
||||||
|
#include "mbedtls/x509.h"
|
||||||
|
#include "mbedtls/error.h"
|
||||||
|
#include "mbedtls/debug.h"
|
||||||
|
#include "mbedtls/timing.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief TLS Connection Parameters
|
||||||
|
*
|
||||||
|
* Defines a type containing TLS specific parameters to be passed down to the
|
||||||
|
* TLS networking layer to create a TLS secured socket.
|
||||||
|
*/
|
||||||
|
typedef struct _TLSDataParams {
|
||||||
|
mbedtls_entropy_context entropy;
|
||||||
|
mbedtls_ctr_drbg_context ctr_drbg;
|
||||||
|
mbedtls_ssl_context ssl;
|
||||||
|
mbedtls_ssl_config conf;
|
||||||
|
uint32_t flags;
|
||||||
|
mbedtls_x509_crt cacert;
|
||||||
|
mbedtls_x509_crt clicert;
|
||||||
|
mbedtls_pk_context pkey;
|
||||||
|
mbedtls_net_context server_fd;
|
||||||
|
}TLSDataParams;
|
||||||
|
|
||||||
|
#define IOTSDKC_NETWORK_MBEDTLS_PLATFORM_H_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif //IOTSDKC_NETWORK_MBEDTLS_PLATFORM_H_H
|
45
components/aws_iot/include/threads_platform.h
Normal file
45
components/aws_iot/include/threads_platform.h
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Additions Copyright 2016 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
* A copy of the License is located at
|
||||||
|
*
|
||||||
|
* http://aws.amazon.com/apache2.0
|
||||||
|
*
|
||||||
|
* or in the "license" file accompanying this file. This file is distributed
|
||||||
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||||
|
* express or implied. See the License for the specific language governing
|
||||||
|
* permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "threads_interface.h"
|
||||||
|
|
||||||
|
#ifndef AWS_IOTSDK_THREADS_PLATFORM_H
|
||||||
|
#define AWS_IOTSDK_THREADS_PLATFORM_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/semphr.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Mutex Type
|
||||||
|
*
|
||||||
|
* definition of the Mutex struct. Platform specific
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct _IoT_Mutex_t {
|
||||||
|
SemaphoreHandle_t mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* AWS_IOTSDK_THREADS_PLATFORM_H */
|
||||||
|
|
||||||
|
|
40
components/aws_iot/include/timer_platform.h
Normal file
40
components/aws_iot/include/timer_platform.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Additions Copyright 2016 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
* A copy of the License is located at
|
||||||
|
*
|
||||||
|
* http://aws.amazon.com/apache2.0
|
||||||
|
*
|
||||||
|
* or in the "license" file accompanying this file. This file is distributed
|
||||||
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||||
|
* express or implied. See the License for the specific language governing
|
||||||
|
* permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AWS_IOT_PLATFORM_H
|
||||||
|
#define AWS_IOT_PLATFORM_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "timer_interface.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* definition of the Timer struct. Platform specific
|
||||||
|
*/
|
||||||
|
struct Timer {
|
||||||
|
uint32_t start_ticks;
|
||||||
|
uint32_t timeout_ticks;
|
||||||
|
uint32_t last_polled_ticks;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* AWS_IOT_PLATFORM_H */
|
408
components/aws_iot/port/network_mbedtls_wrapper.c
Normal file
408
components/aws_iot/port/network_mbedtls_wrapper.c
Normal file
|
@ -0,0 +1,408 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Additions Copyright 2016 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
* A copy of the License is located at
|
||||||
|
*
|
||||||
|
* http://aws.amazon.com/apache2.0
|
||||||
|
*
|
||||||
|
* or in the "license" file accompanying this file. This file is distributed
|
||||||
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||||
|
* express or implied. See the License for the specific language governing
|
||||||
|
* permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <timer_platform.h>
|
||||||
|
#include <network_interface.h>
|
||||||
|
|
||||||
|
#include "aws_iot_config.h"
|
||||||
|
#include "aws_iot_error.h"
|
||||||
|
#include "network_interface.h"
|
||||||
|
#include "network_platform.h"
|
||||||
|
|
||||||
|
#include "mbedtls/esp_debug.h"
|
||||||
|
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_vfs.h"
|
||||||
|
|
||||||
|
static const char *TAG = "aws_iot";
|
||||||
|
|
||||||
|
/* This is the value used for ssl read timeout */
|
||||||
|
#define IOT_SSL_READ_TIMEOUT 10
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a function to do further verification if needed on the cert received.
|
||||||
|
*
|
||||||
|
* Currently used to print debug-level information about each cert.
|
||||||
|
*/
|
||||||
|
static int _iot_tls_verify_cert(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags) {
|
||||||
|
char buf[256];
|
||||||
|
((void) data);
|
||||||
|
|
||||||
|
if (LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG) {
|
||||||
|
ESP_LOGD(TAG, "Verify requested for (Depth %d):", depth);
|
||||||
|
mbedtls_x509_crt_info(buf, sizeof(buf) - 1, "", crt);
|
||||||
|
ESP_LOGD(TAG, "%s", buf);
|
||||||
|
|
||||||
|
if((*flags) == 0) {
|
||||||
|
ESP_LOGD(TAG, " This certificate has no flags");
|
||||||
|
} else {
|
||||||
|
ESP_LOGD(TAG, "Verify result:%s", buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _iot_tls_set_connect_params(Network *pNetwork, const char *pRootCALocation, const char *pDeviceCertLocation,
|
||||||
|
const char *pDevicePrivateKeyLocation, const char *pDestinationURL,
|
||||||
|
uint16_t destinationPort, uint32_t timeout_ms, bool ServerVerificationFlag) {
|
||||||
|
pNetwork->tlsConnectParams.DestinationPort = destinationPort;
|
||||||
|
pNetwork->tlsConnectParams.pDestinationURL = pDestinationURL;
|
||||||
|
pNetwork->tlsConnectParams.pDeviceCertLocation = pDeviceCertLocation;
|
||||||
|
pNetwork->tlsConnectParams.pDevicePrivateKeyLocation = pDevicePrivateKeyLocation;
|
||||||
|
pNetwork->tlsConnectParams.pRootCALocation = pRootCALocation;
|
||||||
|
pNetwork->tlsConnectParams.timeout_ms = timeout_ms;
|
||||||
|
pNetwork->tlsConnectParams.ServerVerificationFlag = ServerVerificationFlag;
|
||||||
|
}
|
||||||
|
|
||||||
|
IoT_Error_t iot_tls_init(Network *pNetwork, const char *pRootCALocation, const char *pDeviceCertLocation,
|
||||||
|
const char *pDevicePrivateKeyLocation, const char *pDestinationURL,
|
||||||
|
uint16_t destinationPort, uint32_t timeout_ms, bool ServerVerificationFlag) {
|
||||||
|
_iot_tls_set_connect_params(pNetwork, pRootCALocation, pDeviceCertLocation, pDevicePrivateKeyLocation,
|
||||||
|
pDestinationURL, destinationPort, timeout_ms, ServerVerificationFlag);
|
||||||
|
|
||||||
|
pNetwork->connect = iot_tls_connect;
|
||||||
|
pNetwork->read = iot_tls_read;
|
||||||
|
pNetwork->write = iot_tls_write;
|
||||||
|
pNetwork->disconnect = iot_tls_disconnect;
|
||||||
|
pNetwork->isConnected = iot_tls_is_connected;
|
||||||
|
pNetwork->destroy = iot_tls_destroy;
|
||||||
|
|
||||||
|
pNetwork->tlsDataParams.flags = 0;
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
IoT_Error_t iot_tls_is_connected(Network *pNetwork) {
|
||||||
|
/* Use this to add implementation which can check for physical layer disconnect */
|
||||||
|
return NETWORK_PHYSICAL_LAYER_CONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
IoT_Error_t iot_tls_connect(Network *pNetwork, TLSConnectParams *params) {
|
||||||
|
int ret = SUCCESS;
|
||||||
|
TLSDataParams *tlsDataParams = NULL;
|
||||||
|
char portBuffer[6];
|
||||||
|
char info_buf[256];
|
||||||
|
|
||||||
|
if(NULL == pNetwork) {
|
||||||
|
return NULL_VALUE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(NULL != params) {
|
||||||
|
_iot_tls_set_connect_params(pNetwork, params->pRootCALocation, params->pDeviceCertLocation,
|
||||||
|
params->pDevicePrivateKeyLocation, params->pDestinationURL,
|
||||||
|
params->DestinationPort, params->timeout_ms, params->ServerVerificationFlag);
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsDataParams = &(pNetwork->tlsDataParams);
|
||||||
|
|
||||||
|
mbedtls_net_init(&(tlsDataParams->server_fd));
|
||||||
|
mbedtls_ssl_init(&(tlsDataParams->ssl));
|
||||||
|
mbedtls_ssl_config_init(&(tlsDataParams->conf));
|
||||||
|
|
||||||
|
#ifdef CONFIG_MBEDTLS_DEBUG
|
||||||
|
mbedtls_esp_enable_debug_log(&(tlsDataParams->conf), 4);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mbedtls_ctr_drbg_init(&(tlsDataParams->ctr_drbg));
|
||||||
|
mbedtls_x509_crt_init(&(tlsDataParams->cacert));
|
||||||
|
mbedtls_x509_crt_init(&(tlsDataParams->clicert));
|
||||||
|
mbedtls_pk_init(&(tlsDataParams->pkey));
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "Seeding the random number generator...");
|
||||||
|
mbedtls_entropy_init(&(tlsDataParams->entropy));
|
||||||
|
if((ret = mbedtls_ctr_drbg_seed(&(tlsDataParams->ctr_drbg), mbedtls_entropy_func, &(tlsDataParams->entropy),
|
||||||
|
(const unsigned char *) TAG, strlen(TAG))) != 0) {
|
||||||
|
ESP_LOGE(TAG, "failed! mbedtls_ctr_drbg_seed returned -0x%x", -ret);
|
||||||
|
return NETWORK_MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load root CA...
|
||||||
|
|
||||||
|
Certs/keys can be paths or they can be raw data. These use a
|
||||||
|
very basic heuristic: if the cert starts with '/' then it's a
|
||||||
|
path, if it's longer than this then it's raw cert data (PEM or DER,
|
||||||
|
neither of which can start with a slash. */
|
||||||
|
if (pNetwork->tlsConnectParams.pRootCALocation[0] == '/') {
|
||||||
|
ESP_LOGD(TAG, "Loading CA root certificate from file ...");
|
||||||
|
ret = mbedtls_x509_crt_parse_file(&(tlsDataParams->cacert), pNetwork->tlsConnectParams.pRootCALocation);
|
||||||
|
} else {
|
||||||
|
ESP_LOGD(TAG, "Loading embedded CA root certificate ...");
|
||||||
|
ret = mbedtls_x509_crt_parse(&(tlsDataParams->cacert), (const unsigned char *)pNetwork->tlsConnectParams.pRootCALocation,
|
||||||
|
strlen(pNetwork->tlsConnectParams.pRootCALocation)+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ret < 0) {
|
||||||
|
ESP_LOGE(TAG, "failed! mbedtls_x509_crt_parse returned -0x%x while parsing root cert", -ret);
|
||||||
|
return NETWORK_X509_ROOT_CRT_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
ESP_LOGD(TAG, "ok (%d skipped)", ret);
|
||||||
|
|
||||||
|
/* Load client certificate... */
|
||||||
|
if (pNetwork->tlsConnectParams.pDeviceCertLocation[0] == '/') {
|
||||||
|
ESP_LOGD(TAG, "Loading client cert from file...");
|
||||||
|
ret = mbedtls_x509_crt_parse_file(&(tlsDataParams->clicert),
|
||||||
|
pNetwork->tlsConnectParams.pDeviceCertLocation);
|
||||||
|
} else {
|
||||||
|
ESP_LOGD(TAG, "Loading embedded client certificate...");
|
||||||
|
ret = mbedtls_x509_crt_parse(&(tlsDataParams->clicert),
|
||||||
|
(const unsigned char *)pNetwork->tlsConnectParams.pDeviceCertLocation,
|
||||||
|
strlen(pNetwork->tlsConnectParams.pDeviceCertLocation)+1);
|
||||||
|
}
|
||||||
|
if(ret != 0) {
|
||||||
|
ESP_LOGE(TAG, "failed! mbedtls_x509_crt_parse returned -0x%x while parsing device cert", -ret);
|
||||||
|
return NETWORK_X509_DEVICE_CRT_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse client private key... */
|
||||||
|
if (pNetwork->tlsConnectParams.pDevicePrivateKeyLocation[0] == '/') {
|
||||||
|
ESP_LOGD(TAG, "Loading client private key from file...");
|
||||||
|
ret = mbedtls_pk_parse_keyfile(&(tlsDataParams->pkey),
|
||||||
|
pNetwork->tlsConnectParams.pDevicePrivateKeyLocation,
|
||||||
|
"");
|
||||||
|
} else {
|
||||||
|
ESP_LOGD(TAG, "Loading embedded client private key...");
|
||||||
|
ret = mbedtls_pk_parse_key(&(tlsDataParams->pkey),
|
||||||
|
(const unsigned char *)pNetwork->tlsConnectParams.pDevicePrivateKeyLocation,
|
||||||
|
strlen(pNetwork->tlsConnectParams.pDevicePrivateKeyLocation)+1,
|
||||||
|
(const unsigned char *)"", 0);
|
||||||
|
}
|
||||||
|
if(ret != 0) {
|
||||||
|
ESP_LOGE(TAG, "failed! mbedtls_pk_parse_key returned -0x%x while parsing private key", -ret);
|
||||||
|
return NETWORK_PK_PRIVATE_KEY_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Done parsing certs */
|
||||||
|
ESP_LOGD(TAG, "ok");
|
||||||
|
snprintf(portBuffer, 6, "%d", pNetwork->tlsConnectParams.DestinationPort);
|
||||||
|
ESP_LOGD(TAG, "Connecting to %s/%s...", pNetwork->tlsConnectParams.pDestinationURL, portBuffer);
|
||||||
|
if((ret = mbedtls_net_connect(&(tlsDataParams->server_fd), pNetwork->tlsConnectParams.pDestinationURL,
|
||||||
|
portBuffer, MBEDTLS_NET_PROTO_TCP)) != 0) {
|
||||||
|
ESP_LOGE(TAG, "failed! mbedtls_net_connect returned -0x%x", -ret);
|
||||||
|
switch(ret) {
|
||||||
|
case MBEDTLS_ERR_NET_SOCKET_FAILED:
|
||||||
|
return NETWORK_ERR_NET_SOCKET_FAILED;
|
||||||
|
case MBEDTLS_ERR_NET_UNKNOWN_HOST:
|
||||||
|
return NETWORK_ERR_NET_UNKNOWN_HOST;
|
||||||
|
case MBEDTLS_ERR_NET_CONNECT_FAILED:
|
||||||
|
default:
|
||||||
|
return NETWORK_ERR_NET_CONNECT_FAILED;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = mbedtls_net_set_block(&(tlsDataParams->server_fd));
|
||||||
|
if(ret != 0) {
|
||||||
|
ESP_LOGE(TAG, "failed! net_set_(non)block() returned -0x%x", -ret);
|
||||||
|
return SSL_CONNECTION_ERROR;
|
||||||
|
} ESP_LOGD(TAG, "ok");
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "Setting up the SSL/TLS structure...");
|
||||||
|
if((ret = mbedtls_ssl_config_defaults(&(tlsDataParams->conf), MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM,
|
||||||
|
MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
|
||||||
|
ESP_LOGE(TAG, "failed! mbedtls_ssl_config_defaults returned -0x%x", -ret);
|
||||||
|
return SSL_CONNECTION_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
mbedtls_ssl_conf_verify(&(tlsDataParams->conf), _iot_tls_verify_cert, NULL);
|
||||||
|
|
||||||
|
if(pNetwork->tlsConnectParams.ServerVerificationFlag == true) {
|
||||||
|
mbedtls_ssl_conf_authmode(&(tlsDataParams->conf), MBEDTLS_SSL_VERIFY_REQUIRED);
|
||||||
|
} else {
|
||||||
|
mbedtls_ssl_conf_authmode(&(tlsDataParams->conf), MBEDTLS_SSL_VERIFY_OPTIONAL);
|
||||||
|
}
|
||||||
|
mbedtls_ssl_conf_rng(&(tlsDataParams->conf), mbedtls_ctr_drbg_random, &(tlsDataParams->ctr_drbg));
|
||||||
|
|
||||||
|
mbedtls_ssl_conf_ca_chain(&(tlsDataParams->conf), &(tlsDataParams->cacert), NULL);
|
||||||
|
ret = mbedtls_ssl_conf_own_cert(&(tlsDataParams->conf), &(tlsDataParams->clicert), &(tlsDataParams->pkey));
|
||||||
|
if(ret != 0) {
|
||||||
|
ESP_LOGE(TAG, "failed! mbedtls_ssl_conf_own_cert returned %d", ret);
|
||||||
|
return SSL_CONNECTION_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
mbedtls_ssl_conf_read_timeout(&(tlsDataParams->conf), pNetwork->tlsConnectParams.timeout_ms);
|
||||||
|
|
||||||
|
if((ret = mbedtls_ssl_setup(&(tlsDataParams->ssl), &(tlsDataParams->conf))) != 0) {
|
||||||
|
ESP_LOGE(TAG, "failed! mbedtls_ssl_setup returned -0x%x", -ret);
|
||||||
|
return SSL_CONNECTION_ERROR;
|
||||||
|
}
|
||||||
|
if((ret = mbedtls_ssl_set_hostname(&(tlsDataParams->ssl), pNetwork->tlsConnectParams.pDestinationURL)) != 0) {
|
||||||
|
ESP_LOGE(TAG, "failed! mbedtls_ssl_set_hostname returned %d", ret);
|
||||||
|
return SSL_CONNECTION_ERROR;
|
||||||
|
}
|
||||||
|
ESP_LOGD(TAG, "SSL state connect : %d ", tlsDataParams->ssl.state);
|
||||||
|
mbedtls_ssl_set_bio(&(tlsDataParams->ssl), &(tlsDataParams->server_fd), mbedtls_net_send, NULL,
|
||||||
|
mbedtls_net_recv_timeout);
|
||||||
|
ESP_LOGD(TAG, "ok");
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "SSL state connect : %d ", tlsDataParams->ssl.state);
|
||||||
|
ESP_LOGD(TAG, "Performing the SSL/TLS handshake...");
|
||||||
|
while((ret = mbedtls_ssl_handshake(&(tlsDataParams->ssl))) != 0) {
|
||||||
|
if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||||
|
ESP_LOGE(TAG, "failed! mbedtls_ssl_handshake returned -0x%x", -ret);
|
||||||
|
if(ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) {
|
||||||
|
ESP_LOGE(TAG, " Unable to verify the server's certificate. ");
|
||||||
|
}
|
||||||
|
return SSL_CONNECTION_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "ok [ Protocol is %s ] [ Ciphersuite is %s ]", mbedtls_ssl_get_version(&(tlsDataParams->ssl)),
|
||||||
|
mbedtls_ssl_get_ciphersuite(&(tlsDataParams->ssl)));
|
||||||
|
if((ret = mbedtls_ssl_get_record_expansion(&(tlsDataParams->ssl))) >= 0) {
|
||||||
|
ESP_LOGD(TAG, " [ Record expansion is %d ]", ret);
|
||||||
|
} else {
|
||||||
|
ESP_LOGD(TAG, " [ Record expansion is unknown (compression) ]");
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "Verifying peer X.509 certificate...");
|
||||||
|
|
||||||
|
if(pNetwork->tlsConnectParams.ServerVerificationFlag == true) {
|
||||||
|
if((tlsDataParams->flags = mbedtls_ssl_get_verify_result(&(tlsDataParams->ssl))) != 0) {
|
||||||
|
ESP_LOGE(TAG, "failed");
|
||||||
|
mbedtls_x509_crt_verify_info(info_buf, sizeof(info_buf), " ! ", tlsDataParams->flags);
|
||||||
|
ESP_LOGE(TAG, "%s", info_buf);
|
||||||
|
ret = SSL_CONNECTION_ERROR;
|
||||||
|
} else {
|
||||||
|
ESP_LOGD(TAG, "ok");
|
||||||
|
ret = SUCCESS;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ESP_LOGW(TAG, " Server Verification skipped");
|
||||||
|
ret = SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG) {
|
||||||
|
if (mbedtls_ssl_get_peer_cert(&(tlsDataParams->ssl)) != NULL) {
|
||||||
|
ESP_LOGD(TAG, "Peer certificate information:");
|
||||||
|
mbedtls_x509_crt_info((char *) info_buf, sizeof(info_buf) - 1, " ", mbedtls_ssl_get_peer_cert(&(tlsDataParams->ssl)));
|
||||||
|
ESP_LOGD(TAG, "%s", info_buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (IoT_Error_t) ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
IoT_Error_t iot_tls_write(Network *pNetwork, unsigned char *pMsg, size_t len, Timer *timer, size_t *written_len) {
|
||||||
|
size_t written_so_far;
|
||||||
|
bool isErrorFlag = false;
|
||||||
|
int frags, ret = 0;
|
||||||
|
TLSDataParams *tlsDataParams = &(pNetwork->tlsDataParams);
|
||||||
|
|
||||||
|
for(written_so_far = 0, frags = 0;
|
||||||
|
written_so_far < len && !has_timer_expired(timer); written_so_far += ret, frags++) {
|
||||||
|
while(!has_timer_expired(timer) &&
|
||||||
|
(ret = mbedtls_ssl_write(&(tlsDataParams->ssl), pMsg + written_so_far, len - written_so_far)) <= 0) {
|
||||||
|
if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||||
|
ESP_LOGE(TAG, "failed! mbedtls_ssl_write returned -0x%x", -ret);
|
||||||
|
/* All other negative return values indicate connection needs to be reset.
|
||||||
|
* Will be caught in ping request so ignored here */
|
||||||
|
isErrorFlag = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(isErrorFlag) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*written_len = written_so_far;
|
||||||
|
|
||||||
|
if(isErrorFlag) {
|
||||||
|
return NETWORK_SSL_WRITE_ERROR;
|
||||||
|
} else if(has_timer_expired(timer) && written_so_far != len) {
|
||||||
|
return NETWORK_SSL_WRITE_TIMEOUT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
IoT_Error_t iot_tls_read(Network *pNetwork, unsigned char *pMsg, size_t len, Timer *timer, size_t *read_len) {
|
||||||
|
TLSDataParams *tlsDataParams = &(pNetwork->tlsDataParams);
|
||||||
|
mbedtls_ssl_context *ssl = &(tlsDataParams->ssl);
|
||||||
|
mbedtls_ssl_config *ssl_conf = &(tlsDataParams->conf);
|
||||||
|
uint32_t read_timeout;
|
||||||
|
size_t rxLen = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
read_timeout = ssl_conf->read_timeout;
|
||||||
|
|
||||||
|
while (len > 0) {
|
||||||
|
|
||||||
|
/* Make sure we never block on read for longer than timer has left,
|
||||||
|
but also that we don't block indefinitely (ie read_timeout > 0) */
|
||||||
|
mbedtls_ssl_conf_read_timeout(ssl_conf, MAX(1, MIN(read_timeout, left_ms(timer))));
|
||||||
|
|
||||||
|
ret = mbedtls_ssl_read(ssl, pMsg, len);
|
||||||
|
|
||||||
|
/* Restore the old timeout */
|
||||||
|
mbedtls_ssl_conf_read_timeout(ssl_conf, read_timeout);
|
||||||
|
|
||||||
|
if (ret > 0) {
|
||||||
|
rxLen += ret;
|
||||||
|
pMsg += ret;
|
||||||
|
len -= ret;
|
||||||
|
} else if (ret == 0 || (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret != MBEDTLS_ERR_SSL_TIMEOUT)) {
|
||||||
|
return NETWORK_SSL_READ_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evaluate timeout after the read to make sure read is done at least once
|
||||||
|
if (has_timer_expired(timer)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len == 0) {
|
||||||
|
*read_len = rxLen;
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rxLen == 0) {
|
||||||
|
return NETWORK_SSL_NOTHING_TO_READ;
|
||||||
|
} else {
|
||||||
|
return NETWORK_SSL_READ_TIMEOUT_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IoT_Error_t iot_tls_disconnect(Network *pNetwork) {
|
||||||
|
mbedtls_ssl_context *ssl = &(pNetwork->tlsDataParams.ssl);
|
||||||
|
int ret = 0;
|
||||||
|
do {
|
||||||
|
ret = mbedtls_ssl_close_notify(ssl);
|
||||||
|
} while(ret == MBEDTLS_ERR_SSL_WANT_WRITE);
|
||||||
|
|
||||||
|
/* All other negative return values indicate connection needs to be reset.
|
||||||
|
* No further action required since this is disconnect call */
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
IoT_Error_t iot_tls_destroy(Network *pNetwork) {
|
||||||
|
TLSDataParams *tlsDataParams = &(pNetwork->tlsDataParams);
|
||||||
|
|
||||||
|
mbedtls_net_free(&(tlsDataParams->server_fd));
|
||||||
|
|
||||||
|
mbedtls_x509_crt_free(&(tlsDataParams->clicert));
|
||||||
|
mbedtls_x509_crt_free(&(tlsDataParams->cacert));
|
||||||
|
mbedtls_pk_free(&(tlsDataParams->pkey));
|
||||||
|
mbedtls_ssl_free(&(tlsDataParams->ssl));
|
||||||
|
mbedtls_ssl_config_free(&(tlsDataParams->conf));
|
||||||
|
mbedtls_ctr_drbg_free(&(tlsDataParams->ctr_drbg));
|
||||||
|
mbedtls_entropy_free(&(tlsDataParams->entropy));
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
104
components/aws_iot/port/threads_freertos.c
Normal file
104
components/aws_iot/port/threads_freertos.c
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Additions Copyright 2016 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
* A copy of the License is located at
|
||||||
|
*
|
||||||
|
* http://aws.amazon.com/apache2.0
|
||||||
|
*
|
||||||
|
* or in the "license" file accompanying this file. This file is distributed
|
||||||
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||||
|
* express or implied. See the License for the specific language governing
|
||||||
|
* permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
|
||||||
|
#include "threads_platform.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the provided mutex
|
||||||
|
*
|
||||||
|
* Call this function to initialize the mutex
|
||||||
|
*
|
||||||
|
* @param IoT_Mutex_t - pointer to the mutex to be initialized
|
||||||
|
* @return IoT_Error_t - error code indicating result of operation
|
||||||
|
*/
|
||||||
|
IoT_Error_t aws_iot_thread_mutex_init(IoT_Mutex_t *pMutex) {
|
||||||
|
|
||||||
|
pMutex->mutex = xSemaphoreCreateRecursiveMutex();
|
||||||
|
return pMutex->mutex ? SUCCESS : MUTEX_INIT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Lock the provided mutex
|
||||||
|
*
|
||||||
|
* Call this function to lock the mutex before performing a state change
|
||||||
|
* Blocking, thread will block until lock request fails
|
||||||
|
*
|
||||||
|
* @param IoT_Mutex_t - pointer to the mutex to be locked
|
||||||
|
* @return IoT_Error_t - error code indicating result of operation
|
||||||
|
*/
|
||||||
|
IoT_Error_t aws_iot_thread_mutex_lock(IoT_Mutex_t *pMutex) {
|
||||||
|
xSemaphoreTakeRecursive(pMutex->mutex, portMAX_DELAY);
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Try to lock the provided mutex
|
||||||
|
*
|
||||||
|
* Call this function to attempt to lock the mutex before performing a state change
|
||||||
|
* Non-Blocking, immediately returns with failure if lock attempt fails
|
||||||
|
*
|
||||||
|
* @param IoT_Mutex_t - pointer to the mutex to be locked
|
||||||
|
* @return IoT_Error_t - error code indicating result of operation
|
||||||
|
*/
|
||||||
|
IoT_Error_t aws_iot_thread_mutex_trylock(IoT_Mutex_t *pMutex) {
|
||||||
|
if (xSemaphoreTakeRecursive(pMutex->mutex, 0)) {
|
||||||
|
return SUCCESS;
|
||||||
|
} else {
|
||||||
|
return MUTEX_LOCK_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unlock the provided mutex
|
||||||
|
*
|
||||||
|
* Call this function to unlock the mutex before performing a state change
|
||||||
|
*
|
||||||
|
* @param IoT_Mutex_t - pointer to the mutex to be unlocked
|
||||||
|
* @return IoT_Error_t - error code indicating result of operation
|
||||||
|
*/
|
||||||
|
IoT_Error_t aws_iot_thread_mutex_unlock(IoT_Mutex_t *pMutex) {
|
||||||
|
if (xSemaphoreGiveRecursive(pMutex->mutex)) {
|
||||||
|
return SUCCESS;
|
||||||
|
} else {
|
||||||
|
return MUTEX_UNLOCK_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destroy the provided mutex
|
||||||
|
*
|
||||||
|
* Call this function to destroy the mutex
|
||||||
|
*
|
||||||
|
* @param IoT_Mutex_t - pointer to the mutex to be destroyed
|
||||||
|
* @return IoT_Error_t - error code indicating result of operation
|
||||||
|
*/
|
||||||
|
IoT_Error_t aws_iot_thread_mutex_destroy(IoT_Mutex_t *pMutex) {
|
||||||
|
vSemaphoreDelete(pMutex->mutex);
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
83
components/aws_iot/port/timer.c
Normal file
83
components/aws_iot/port/timer.c
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Additions Copyright 2016 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
* A copy of the License is located at
|
||||||
|
*
|
||||||
|
* http://aws.amazon.com/apache2.0
|
||||||
|
*
|
||||||
|
* or in the "license" file accompanying this file. This file is distributed
|
||||||
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||||
|
* express or implied. See the License for the specific language governing
|
||||||
|
* permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file timer.c
|
||||||
|
* @brief FreeRTOS implementation of the timer interface uses ticks.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include "timer_platform.h"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
|
||||||
|
const static char *TAG = "aws_timer";
|
||||||
|
|
||||||
|
bool has_timer_expired(Timer *timer) {
|
||||||
|
uint32_t now = xTaskGetTickCount();
|
||||||
|
bool expired = (now - timer->start_ticks) >= timer->timeout_ticks;
|
||||||
|
|
||||||
|
/* AWS IoT SDK isn't very RTOS friendly because it polls for "done
|
||||||
|
timers" a lot without ever sleeping on them. So we hack in some
|
||||||
|
amount of sleeping here: if it seems like the caller is polling
|
||||||
|
an unexpired timer in a tight loop then we delay a tick to let
|
||||||
|
things progress elsewhere.
|
||||||
|
*/
|
||||||
|
if(!expired && now == timer->last_polled_ticks) {
|
||||||
|
vTaskDelay(1);
|
||||||
|
}
|
||||||
|
timer->last_polled_ticks = now;
|
||||||
|
return expired;
|
||||||
|
}
|
||||||
|
|
||||||
|
void countdown_ms(Timer *timer, uint32_t timeout) {
|
||||||
|
timer->start_ticks = xTaskGetTickCount();
|
||||||
|
timer->timeout_ticks = timeout / portTICK_PERIOD_MS;
|
||||||
|
timer->last_polled_ticks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t left_ms(Timer *timer) {
|
||||||
|
uint32_t now = xTaskGetTickCount();
|
||||||
|
uint32_t elapsed = now - timer->start_ticks;
|
||||||
|
if (elapsed < timer->timeout_ticks) {
|
||||||
|
return (timer->timeout_ticks - elapsed) * portTICK_PERIOD_MS;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void countdown_sec(Timer *timer, uint32_t timeout) {
|
||||||
|
if (timeout > UINT32_MAX / 1000) {
|
||||||
|
ESP_LOGE(TAG, "timeout is out of range: %ds", timeout);
|
||||||
|
}
|
||||||
|
countdown_ms(timer, timeout * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_timer(Timer *timer) {
|
||||||
|
timer->start_ticks = 0;
|
||||||
|
timer->timeout_ticks = 0;
|
||||||
|
timer->last_polled_ticks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -23,7 +23,7 @@ BOOTLOADER_OFFSET := 0x1000
|
||||||
|
|
||||||
# Custom recursive make for bootloader sub-project
|
# Custom recursive make for bootloader sub-project
|
||||||
BOOTLOADER_MAKE=+$(MAKE) -C $(BOOTLOADER_COMPONENT_PATH)/src \
|
BOOTLOADER_MAKE=+$(MAKE) -C $(BOOTLOADER_COMPONENT_PATH)/src \
|
||||||
V=$(V) BUILD_DIR_BASE=$(BOOTLOADER_BUILD_DIR) TEST_COMPONENTS=
|
V=$(V) BUILD_DIR_BASE=$(BOOTLOADER_BUILD_DIR) TEST_COMPONENTS= TESTS_ALL=
|
||||||
|
|
||||||
.PHONY: bootloader-clean bootloader-flash bootloader $(BOOTLOADER_BIN)
|
.PHONY: bootloader-clean bootloader-flash bootloader $(BOOTLOADER_BIN)
|
||||||
|
|
||||||
|
|
|
@ -114,7 +114,15 @@ esp_err_t uart_set_stop_bits(uart_port_t uart_num, uart_stop_bits_t stop_bit)
|
||||||
{
|
{
|
||||||
UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
|
UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
|
||||||
UART_CHECK((stop_bit < UART_STOP_BITS_MAX), "stop bit error", ESP_FAIL);
|
UART_CHECK((stop_bit < UART_STOP_BITS_MAX), "stop bit error", ESP_FAIL);
|
||||||
|
|
||||||
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
|
UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
|
||||||
|
//workaround for hardware bug, when uart stop bit set as 2-bit mode.
|
||||||
|
if (stop_bit == UART_STOP_BITS_2) {
|
||||||
|
stop_bit = UART_STOP_BITS_1;
|
||||||
|
UART[uart_num]->rs485_conf.dl1_en = 1;
|
||||||
|
} else {
|
||||||
|
UART[uart_num]->rs485_conf.dl1_en = 0;
|
||||||
|
}
|
||||||
UART[uart_num]->conf0.stop_bit_num = stop_bit;
|
UART[uart_num]->conf0.stop_bit_num = stop_bit;
|
||||||
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
|
UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
|
@ -123,7 +131,12 @@ esp_err_t uart_set_stop_bits(uart_port_t uart_num, uart_stop_bits_t stop_bit)
|
||||||
esp_err_t uart_get_stop_bits(uart_port_t uart_num, uart_stop_bits_t* stop_bit)
|
esp_err_t uart_get_stop_bits(uart_port_t uart_num, uart_stop_bits_t* stop_bit)
|
||||||
{
|
{
|
||||||
UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
|
UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
|
||||||
|
//workaround for hardware bug, when uart stop bit set as 2-bit mode.
|
||||||
|
if (UART[uart_num]->rs485_conf.dl1_en == 1 && UART[uart_num]->conf0.stop_bit_num == UART_STOP_BITS_1) {
|
||||||
|
(*stop_bit) = UART_STOP_BITS_2;
|
||||||
|
} else {
|
||||||
(*stop_bit) = UART[uart_num]->conf0.stop_bit_num;
|
(*stop_bit) = UART[uart_num]->conf0.stop_bit_num;
|
||||||
|
}
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -437,12 +450,13 @@ esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_conf
|
||||||
}
|
}
|
||||||
uart_set_hw_flow_ctrl(uart_num, uart_config->flow_ctrl, uart_config->rx_flow_ctrl_thresh);
|
uart_set_hw_flow_ctrl(uart_num, uart_config->flow_ctrl, uart_config->rx_flow_ctrl_thresh);
|
||||||
uart_set_baudrate(uart_num, uart_config->baud_rate);
|
uart_set_baudrate(uart_num, uart_config->baud_rate);
|
||||||
|
|
||||||
UART[uart_num]->conf0.val = (
|
UART[uart_num]->conf0.val = (
|
||||||
(uart_config->parity << UART_PARITY_S)
|
(uart_config->parity << UART_PARITY_S)
|
||||||
| (uart_config->stop_bits << UART_STOP_BIT_NUM_S)
|
|
||||||
| (uart_config->data_bits << UART_BIT_NUM_S)
|
| (uart_config->data_bits << UART_BIT_NUM_S)
|
||||||
| ((uart_config->flow_ctrl & UART_HW_FLOWCTRL_CTS) ? UART_TX_FLOW_EN : 0x0)
|
| ((uart_config->flow_ctrl & UART_HW_FLOWCTRL_CTS) ? UART_TX_FLOW_EN : 0x0)
|
||||||
| UART_TICK_REF_ALWAYS_ON_M);
|
| UART_TICK_REF_ALWAYS_ON_M);
|
||||||
|
uart_set_stop_bits(uart_num, uart_config->stop_bits);
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit ffe5a4c14fe9c933c776fadc62fa9d409929e6f9
|
Subproject commit c88869b1aca5a062d1ebc5e0199fd8720cb08710
|
|
@ -69,10 +69,26 @@ erase_flash:
|
||||||
|
|
||||||
MONITORBAUD ?= $(CONFIG_MONITOR_BAUD)
|
MONITORBAUD ?= $(CONFIG_MONITOR_BAUD)
|
||||||
|
|
||||||
|
MONITOR_PYTHON := $(PYTHON)
|
||||||
|
|
||||||
|
ifeq ("$(OS)","Windows_NT")
|
||||||
|
# miniterm and idf_monitor both need a Windows Console PTY in order
|
||||||
|
# to correctly handle user input
|
||||||
|
MONITOR_PYTHON := winpty $(PYTHON)
|
||||||
|
endif
|
||||||
|
|
||||||
# note: if you want to run miniterm from command line, can simply run
|
# note: if you want to run miniterm from command line, can simply run
|
||||||
# miniterm.py on the console. The '$(PYTHON) -m serial.tools.miniterm'
|
# miniterm.py on the console. The '$(PYTHON) -m serial.tools.miniterm'
|
||||||
# is to allow for the $(PYTHON) variable overriding the python path.
|
# is to allow for the $(PYTHON) variable overriding the python path.
|
||||||
|
simple_monitor: $(call prereq_if_explicit,%flash)
|
||||||
|
$(MONITOR_PYTHON) -m serial.tools.miniterm --rts 0 --dtr 0 --raw $(ESPPORT) $(MONITORBAUD)
|
||||||
|
|
||||||
monitor: $(call prereq_if_explicit,%flash)
|
monitor: $(call prereq_if_explicit,%flash)
|
||||||
$(PYTHON) -m serial.tools.miniterm --rts 0 --dtr 0 --raw $(ESPPORT) $(MONITORBAUD)
|
$(summary) MONITOR
|
||||||
|
[ -f $(APP_ELF) ] || echo "*** 'make monitor' target requires an app to be compiled and flashed first."
|
||||||
|
[ -f $(APP_ELF) ] || echo "*** Run 'make flash monitor' to build, flash and monitor"
|
||||||
|
[ -f $(APP_ELF) ] || echo "*** Or alternatively 'make simple_monitor' to view the serial port as-is."
|
||||||
|
[ -f $(APP_ELF) ] || exit 1
|
||||||
|
$(MONITOR_PYTHON) $(IDF_PATH)/tools/idf_monitor.py --port $(ESPPORT) --make "$(MAKE)" $(APP_ELF)
|
||||||
|
|
||||||
.PHONY: erase_flash
|
.PHONY: erase_flash
|
||||||
|
|
108
components/fatfs/Kconfig
Normal file
108
components/fatfs/Kconfig
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
menu "FAT Filesystem support"
|
||||||
|
|
||||||
|
choice FATFS_CHOOSE_CODEPAGE
|
||||||
|
prompt "OEM Code Page"
|
||||||
|
default FATFS_CODEPAGE_ASCII
|
||||||
|
help
|
||||||
|
OEM code page used for file name encodings. Required to
|
||||||
|
be set to a non-ASCII value to use Long Filenames.
|
||||||
|
|
||||||
|
config FATFS_CODEPAGE_ASCII
|
||||||
|
bool "ASCII (CP1, no long filenames)"
|
||||||
|
config FATFS_CODEPAGE_437
|
||||||
|
bool "US (CP437)"
|
||||||
|
config FATFS_CODEPAGE_720
|
||||||
|
bool "Arabic (CP720)"
|
||||||
|
config FATFS_CODEPAGE_737
|
||||||
|
bool "Greek (CP737)"
|
||||||
|
config FATFS_CODEPAGE_771
|
||||||
|
bool "KBL (CP771)"
|
||||||
|
config FATFS_CODEPAGE_775
|
||||||
|
bool "Baltic (CP775)"
|
||||||
|
config FATFS_CODEPAGE_850
|
||||||
|
bool "Latin 1 (CP850)"
|
||||||
|
config FATFS_CODEPAGE_852
|
||||||
|
bool "Latin 2 (CP852)"
|
||||||
|
config FATFS_CODEPAGE_855
|
||||||
|
bool "Cyrillic (CP855)"
|
||||||
|
config FATFS_CODEPAGE_857
|
||||||
|
bool "Turkish (CP857)"
|
||||||
|
config FATFS_CODEPAGE_860
|
||||||
|
bool "Portugese (CP860)"
|
||||||
|
config FATFS_CODEPAGE_861
|
||||||
|
bool "Icelandic (CP861)"
|
||||||
|
config FATFS_CODEPAGE_862
|
||||||
|
bool "Hebrew (CP862)"
|
||||||
|
config FATFS_CODEPAGE_863
|
||||||
|
bool "Canadian French (CP863)"
|
||||||
|
config FATFS_CODEPAGE_864
|
||||||
|
bool "Arabic (CP864)"
|
||||||
|
config FATFS_CODEPAGE_865
|
||||||
|
bool "Nordic (CP865)"
|
||||||
|
config FATFS_CODEPAGE_866
|
||||||
|
bool "Russian (CP866)"
|
||||||
|
config FATFS_CODEPAGE_869
|
||||||
|
bool "Greek 2 (CP869)"
|
||||||
|
config FATFS_CODEPAGE_932
|
||||||
|
bool "Japanese (DBCS) (CP932)"
|
||||||
|
config FATFS_CODEPAGE_936
|
||||||
|
bool "Simplified Chinese (DBCS) (CP936)"
|
||||||
|
config FATFS_CODEPAGE_949
|
||||||
|
bool "Korean (DBCS) (CP949)"
|
||||||
|
config FATFS_CODEPAGE_950
|
||||||
|
bool "Traditional Chinese (DBCS) (CP950)"
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
config FATFS_CODEPAGE
|
||||||
|
int
|
||||||
|
default 1 if FATFS_CODEPAGE_ASCII
|
||||||
|
default 437 if FATFS_CODEPAGE_437
|
||||||
|
default 720 if FATFS_CODEPAGE_720
|
||||||
|
default 737 if FATFS_CODEPAGE_737
|
||||||
|
default 771 if FATFS_CODEPAGE_771
|
||||||
|
default 775 if FATFS_CODEPAGE_775
|
||||||
|
default 850 if FATFS_CODEPAGE_850
|
||||||
|
default 852 if FATFS_CODEPAGE_852
|
||||||
|
default 855 if FATFS_CODEPAGE_855
|
||||||
|
default 857 if FATFS_CODEPAGE_857
|
||||||
|
default 860 if FATFS_CODEPAGE_860
|
||||||
|
default 861 if FATFS_CODEPAGE_861
|
||||||
|
default 862 if FATFS_CODEPAGE_862
|
||||||
|
default 863 if FATFS_CODEPAGE_863
|
||||||
|
default 864 if FATFS_CODEPAGE_864
|
||||||
|
default 865 if FATFS_CODEPAGE_865
|
||||||
|
default 866 if FATFS_CODEPAGE_866
|
||||||
|
default 869 if FATFS_CODEPAGE_869
|
||||||
|
default 932 if FATFS_CODEPAGE_932
|
||||||
|
default 936 if FATFS_CODEPAGE_936
|
||||||
|
default 949 if FATFS_CODEPAGE_949
|
||||||
|
default 950 if FATFS_CODEPAGE_950
|
||||||
|
default 1
|
||||||
|
|
||||||
|
choice FATFS_LONG_FILENAMES
|
||||||
|
prompt "Long filename support"
|
||||||
|
default FATFS_LFN_NONE
|
||||||
|
depends on !FATFS_CODEPAGE_ASCII
|
||||||
|
help
|
||||||
|
Support long filenames in FAT. Long filename data increases
|
||||||
|
memory usage. FATFS can be configured to store the buffer for
|
||||||
|
long filename data in stack or heap.
|
||||||
|
|
||||||
|
config FATFS_LFN_NONE
|
||||||
|
bool "No long filenames"
|
||||||
|
config FATFS_LFN_HEAP
|
||||||
|
bool "Long filename buffer in heap"
|
||||||
|
config FATFS_LFN_STACK
|
||||||
|
bool "Long filename buffer on stack"
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
config FATFS_MAX_LFN
|
||||||
|
int "Max long filename length"
|
||||||
|
depends on !FATFS_LFN_NONE
|
||||||
|
default 255
|
||||||
|
range 12 255
|
||||||
|
help
|
||||||
|
Maximum long filename length. Can be reduced to save RAM.
|
||||||
|
|
||||||
|
endmenu
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include "sdkconfig.h"
|
||||||
/*---------------------------------------------------------------------------/
|
/*---------------------------------------------------------------------------/
|
||||||
/ FatFs - FAT file system module configuration file
|
/ FatFs - FAT file system module configuration file
|
||||||
/---------------------------------------------------------------------------*/
|
/---------------------------------------------------------------------------*/
|
||||||
|
@ -69,7 +70,7 @@
|
||||||
/ Locale and Namespace Configurations
|
/ Locale and Namespace Configurations
|
||||||
/---------------------------------------------------------------------------*/
|
/---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#define _CODE_PAGE 1
|
#define _CODE_PAGE CONFIG_FATFS_CODEPAGE
|
||||||
/* This option specifies the OEM code page to be used on the target system.
|
/* This option specifies the OEM code page to be used on the target system.
|
||||||
/ Incorrect setting of the code page can cause a file open failure.
|
/ Incorrect setting of the code page can cause a file open failure.
|
||||||
/
|
/
|
||||||
|
@ -97,9 +98,17 @@
|
||||||
/ 950 - Traditional Chinese (DBCS)
|
/ 950 - Traditional Chinese (DBCS)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#if defined(CONFIG_FATFS_LFN_STACK)
|
||||||
|
#define _USE_LFN 2
|
||||||
|
#elif defined(CONFIG_FATFS_LFN_HEAP)
|
||||||
|
#define _USE_LFN 3
|
||||||
|
#else /* CONFIG_FATFS_LFN_NONE */
|
||||||
#define _USE_LFN 0
|
#define _USE_LFN 0
|
||||||
#define _MAX_LFN 255
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_FATFS_MAX_LFN
|
||||||
|
#define _MAX_LFN CONFIG_FATFS_MAX_LFN
|
||||||
|
#endif
|
||||||
/* The _USE_LFN switches the support of long file name (LFN).
|
/* The _USE_LFN switches the support of long file name (LFN).
|
||||||
/
|
/
|
||||||
/ 0: Disable support of LFN. _MAX_LFN has no effect.
|
/ 0: Disable support of LFN. _MAX_LFN has no effect.
|
||||||
|
|
3870
components/fatfs/src/option/cc932.c.inc
Normal file
3870
components/fatfs/src/option/cc932.c.inc
Normal file
File diff suppressed because it is too large
Load diff
11045
components/fatfs/src/option/cc936.c.inc
Normal file
11045
components/fatfs/src/option/cc936.c.inc
Normal file
File diff suppressed because it is too large
Load diff
8674
components/fatfs/src/option/cc949.c.inc
Normal file
8674
components/fatfs/src/option/cc949.c.inc
Normal file
File diff suppressed because it is too large
Load diff
6900
components/fatfs/src/option/cc950.c.inc
Normal file
6900
components/fatfs/src/option/cc950.c.inc
Normal file
File diff suppressed because it is too large
Load diff
388
components/fatfs/src/option/ccsbcs.c.inc
Normal file
388
components/fatfs/src/option/ccsbcs.c.inc
Normal file
|
@ -0,0 +1,388 @@
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
/* Unicode - Local code bidirectional converter (C)ChaN, 2015 */
|
||||||
|
/* (SBCS code pages) */
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
/* 437 U.S.
|
||||||
|
/ 720 Arabic
|
||||||
|
/ 737 Greek
|
||||||
|
/ 771 KBL
|
||||||
|
/ 775 Baltic
|
||||||
|
/ 850 Latin 1
|
||||||
|
/ 852 Latin 2
|
||||||
|
/ 855 Cyrillic
|
||||||
|
/ 857 Turkish
|
||||||
|
/ 860 Portuguese
|
||||||
|
/ 861 Icelandic
|
||||||
|
/ 862 Hebrew
|
||||||
|
/ 863 Canadian French
|
||||||
|
/ 864 Arabic
|
||||||
|
/ 865 Nordic
|
||||||
|
/ 866 Russian
|
||||||
|
/ 869 Greek 2
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../ff.h"
|
||||||
|
|
||||||
|
|
||||||
|
#if _CODE_PAGE == 437
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP437(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
|
||||||
|
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
|
||||||
|
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||||
|
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||||
|
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
|
||||||
|
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 720
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP720(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000,
|
||||||
|
0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9, 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627,
|
||||||
|
0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||||
|
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||||
|
0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A,
|
||||||
|
0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 737
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP737(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0,
|
||||||
|
0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8,
|
||||||
|
0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||||
|
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||||
|
0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD, 0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E,
|
||||||
|
0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 771
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP771(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
|
||||||
|
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
|
||||||
|
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||||
|
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x0104, 0x0105, 0x010C, 0x010D,
|
||||||
|
0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
|
||||||
|
0x0118, 0x0119, 0x0116, 0x0117, 0x012E, 0x012F, 0x0160, 0x0161, 0x0172, 0x0173, 0x016A, 0x016B, 0x017D, 0x017E, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 775
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP775(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5,
|
||||||
|
0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4,
|
||||||
|
0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118, 0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D,
|
||||||
|
0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B, 0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||||
|
0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144, 0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019,
|
||||||
|
0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E, 0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 850
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP850(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
|
||||||
|
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
|
||||||
|
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
|
||||||
|
0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
|
||||||
|
0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,
|
||||||
|
0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 852
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP852(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106,
|
||||||
|
0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D,
|
||||||
|
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A, 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
|
||||||
|
0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE, 0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580,
|
||||||
|
0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4,
|
||||||
|
0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 855
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP855(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408,
|
||||||
|
0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A,
|
||||||
|
0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438, 0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
|
||||||
|
0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E, 0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580,
|
||||||
|
0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443, 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116,
|
||||||
|
0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D, 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 857
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP857(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5,
|
||||||
|
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F,
|
||||||
|
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
|
||||||
|
0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0x0000, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
|
||||||
|
0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000, 0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4,
|
||||||
|
0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 860
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP860(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E3, 0x00E0, 0x00C1, 0x00E7, 0x00EA, 0x00CA, 0x00E8, 0x00CD, 0x00D4, 0x00EC, 0x00C3, 0x00C2,
|
||||||
|
0x00C9, 0x00C0, 0x00C8, 0x00F4, 0x00F5, 0x00F2, 0x00DA, 0x00F9, 0x00CC, 0x00D5, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x20A7, 0x00D3,
|
||||||
|
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00D2, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||||
|
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||||
|
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
|
||||||
|
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 861
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP861(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00D0, 0x00F0, 0x00DE, 0x00C4, 0x00C5,
|
||||||
|
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00FE, 0x00FB, 0x00DD, 0x00FD, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,
|
||||||
|
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00C1, 0x00CD, 0x00D3, 0x00DA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||||
|
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||||
|
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
|
||||||
|
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 862
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP862(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
|
||||||
|
0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
|
||||||
|
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||||
|
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||||
|
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
|
||||||
|
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 863
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP863(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00C2, 0x00E0, 0x00B6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x2017, 0x00C0,
|
||||||
|
0x00C9, 0x00C8, 0x00CA, 0x00F4, 0x00CB, 0x00CF, 0x00FB, 0x00F9, 0x00A4, 0x00D4, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x00DB, 0x0192,
|
||||||
|
0x00A6, 0x00B4, 0x00F3, 0x00FA, 0x00A8, 0x00BB, 0x00B3, 0x00AF, 0x00CE, 0x3210, 0x00AC, 0x00BD, 0x00BC, 0x00BE, 0x00AB, 0x00BB,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||||
|
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||||
|
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2219,
|
||||||
|
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 864
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP864(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x00B0, 0x00B7, 0x2219, 0x221A, 0x2592, 0x2500, 0x2502, 0x253C, 0x2524, 0x252C, 0x251C, 0x2534, 0x2510, 0x250C, 0x2514, 0x2518,
|
||||||
|
0x03B2, 0x221E, 0x03C6, 0x00B1, 0x00BD, 0x00BC, 0x2248, 0x00AB, 0x00BB, 0xFEF7, 0xFEF8, 0x0000, 0x0000, 0xFEFB, 0xFEFC, 0x0000,
|
||||||
|
0x00A0, 0x00AD, 0xFE82, 0x00A3, 0x00A4, 0xFE84, 0x0000, 0x20AC, 0xFE8E, 0xFE8F, 0xFE95, 0xFE99, 0x060C, 0xFE9D, 0xFEA1, 0xFEA5,
|
||||||
|
0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669, 0xFED1, 0x061B, 0xFEB1, 0xFEB5, 0xFEB9, 0x061F,
|
||||||
|
0x00A2, 0xFE80, 0xFE81, 0xFE83, 0xFE85, 0xFECA, 0xFE8B, 0xFE8D, 0xFE91, 0xFE93, 0xFE97, 0xFE9B, 0xFE9F, 0xFEA3, 0xFEA7, 0xFEA9,
|
||||||
|
0xFEAB, 0xFEAD, 0xFEAF, 0xFEB3, 0xFEB7, 0xFEBB, 0xFEBF, 0xFEC1, 0xFEC5, 0xFECB, 0xFECF, 0x00A6, 0x00AC, 0x00F7, 0x00D7, 0xFEC9,
|
||||||
|
0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB, 0xFEED, 0xFEEF, 0xFEF3, 0xFEBD, 0xFECC, 0xFECE, 0xFECD, 0xFEE1,
|
||||||
|
0xFE7D, 0x0651, 0xFEE5, 0xFEE9, 0xFEEC, 0xFEF0, 0xFEF2, 0xFED0, 0xFED5, 0xFEF5, 0xFEF6, 0xFEDD, 0xFED9, 0xFEF1, 0x25A0, 0x0000
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 865
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP865(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
|
||||||
|
0x00C5, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,
|
||||||
|
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00A4,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||||
|
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||||
|
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
|
||||||
|
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 866
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP866(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
|
||||||
|
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
|
||||||
|
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||||
|
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||||
|
0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
|
||||||
|
0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 869
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP869(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x0386, 0x00B7, 0x00B7, 0x00AC, 0x00A6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389,
|
||||||
|
0x038A, 0x03AA, 0x038C, 0x00B7, 0x00B7, 0x038E, 0x03AB, 0x00A9, 0x038F, 0x00B2, 0x00B3, 0x03AC, 0x00A3, 0x03AD, 0x03AE, 0x03AF,
|
||||||
|
0x03CA, 0x0390, 0x03CC, 0x03CD, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00BD, 0x0398, 0x0399, 0x00AB, 0x00BB,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x039A, 0x039B, 0x039C, 0x039D, 0x2563, 0x2551, 0x2557, 0x255D, 0x039E, 0x039F, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0A30, 0x03A1, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x03A3,
|
||||||
|
0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x2518, 0x250C, 0x2588, 0x2584, 0x03B4, 0x03B5, 0x2580,
|
||||||
|
0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x0384,
|
||||||
|
0x00AD, 0x00B1, 0x03C5, 0x03C6, 0x03C7, 0x00A7, 0x03C8, 0x0385, 0x00B0, 0x00A8, 0x03C9, 0x03CB, 0x03B0, 0x03CE, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if !_TBLDEF || !_USE_LFN
|
||||||
|
#error This file is not needed at current configuration. Remove from the project.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
WCHAR ff_convert ( /* Converted character, Returns zero on error */
|
||||||
|
WCHAR chr, /* Character code to be converted */
|
||||||
|
UINT dir /* 0: Unicode to OEM code, 1: OEM code to Unicode */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
WCHAR c;
|
||||||
|
|
||||||
|
|
||||||
|
if (chr < 0x80) { /* ASCII */
|
||||||
|
c = chr;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (dir) { /* OEM code to Unicode */
|
||||||
|
c = (chr >= 0x100) ? 0 : Tbl[chr - 0x80];
|
||||||
|
|
||||||
|
} else { /* Unicode to OEM code */
|
||||||
|
for (c = 0; c < 0x80; c++) {
|
||||||
|
if (chr == Tbl[c]) break;
|
||||||
|
}
|
||||||
|
c = (c + 0x80) & 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
WCHAR ff_wtoupper ( /* Returns upper converted character */
|
||||||
|
WCHAR chr /* Unicode character to be upper converted (BMP only) */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
/* Compressed upper conversion table */
|
||||||
|
static const WCHAR cvt1[] = { /* U+0000 - U+0FFF */
|
||||||
|
/* Basic Latin */
|
||||||
|
0x0061,0x031A,
|
||||||
|
/* Latin-1 Supplement */
|
||||||
|
0x00E0,0x0317, 0x00F8,0x0307, 0x00FF,0x0001,0x0178,
|
||||||
|
/* Latin Extended-A */
|
||||||
|
0x0100,0x0130, 0x0132,0x0106, 0x0139,0x0110, 0x014A,0x012E, 0x0179,0x0106,
|
||||||
|
/* Latin Extended-B */
|
||||||
|
0x0180,0x004D,0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,0x0187,0x0189,0x018A,0x018B,0x018B,0x018D,0x018E,0x018F,0x0190,0x0191,0x0191,0x0193,0x0194,0x01F6,0x0196,0x0197,0x0198,0x0198,0x023D,0x019B,0x019C,0x019D,0x0220,0x019F,0x01A0,0x01A0,0x01A2,0x01A2,0x01A4,0x01A4,0x01A6,0x01A7,0x01A7,0x01A9,0x01AA,0x01AB,0x01AC,0x01AC,0x01AE,0x01AF,0x01AF,0x01B1,0x01B2,0x01B3,0x01B3,0x01B5,0x01B5,0x01B7,0x01B8,0x01B8,0x01BA,0x01BB,0x01BC,0x01BC,0x01BE,0x01F7,0x01C0,0x01C1,0x01C2,0x01C3,0x01C4,0x01C5,0x01C4,0x01C7,0x01C8,0x01C7,0x01CA,0x01CB,0x01CA,
|
||||||
|
0x01CD,0x0110, 0x01DD,0x0001,0x018E, 0x01DE,0x0112, 0x01F3,0x0003,0x01F1,0x01F4,0x01F4, 0x01F8,0x0128,
|
||||||
|
0x0222,0x0112, 0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241, 0x0246,0x010A,
|
||||||
|
/* IPA Extensions */
|
||||||
|
0x0253,0x0040,0x0181,0x0186,0x0255,0x0189,0x018A,0x0258,0x018F,0x025A,0x0190,0x025C,0x025D,0x025E,0x025F,0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,0x0197,0x0196,0x026A,0x2C62,0x026C,0x026D,0x026E,0x019C,0x0270,0x0271,0x019D,0x0273,0x0274,0x019F,0x0276,0x0277,0x0278,0x0279,0x027A,0x027B,0x027C,0x2C64,0x027E,0x027F,0x01A6,0x0281,0x0282,0x01A9,0x0284,0x0285,0x0286,0x0287,0x01AE,0x0244,0x01B1,0x01B2,0x0245,0x028D,0x028E,0x028F,0x0290,0x0291,0x01B7,
|
||||||
|
/* Greek, Coptic */
|
||||||
|
0x037B,0x0003,0x03FD,0x03FE,0x03FF, 0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A, 0x03B1,0x0311,
|
||||||
|
0x03C2,0x0002,0x03A3,0x03A3, 0x03C4,0x0308, 0x03CC,0x0003,0x038C,0x038E,0x038F, 0x03D8,0x0118,
|
||||||
|
0x03F2,0x000A,0x03F9,0x03F3,0x03F4,0x03F5,0x03F6,0x03F7,0x03F7,0x03F9,0x03FA,0x03FA,
|
||||||
|
/* Cyrillic */
|
||||||
|
0x0430,0x0320, 0x0450,0x0710, 0x0460,0x0122, 0x048A,0x0136, 0x04C1,0x010E, 0x04CF,0x0001,0x04C0, 0x04D0,0x0144,
|
||||||
|
/* Armenian */
|
||||||
|
0x0561,0x0426,
|
||||||
|
|
||||||
|
0x0000
|
||||||
|
};
|
||||||
|
static const WCHAR cvt2[] = { /* U+1000 - U+FFFF */
|
||||||
|
/* Phonetic Extensions */
|
||||||
|
0x1D7D,0x0001,0x2C63,
|
||||||
|
/* Latin Extended Additional */
|
||||||
|
0x1E00,0x0196, 0x1EA0,0x015A,
|
||||||
|
/* Greek Extended */
|
||||||
|
0x1F00,0x0608, 0x1F10,0x0606, 0x1F20,0x0608, 0x1F30,0x0608, 0x1F40,0x0606,
|
||||||
|
0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F, 0x1F60,0x0608,
|
||||||
|
0x1F70,0x000E,0x1FBA,0x1FBB,0x1FC8,0x1FC9,0x1FCA,0x1FCB,0x1FDA,0x1FDB,0x1FF8,0x1FF9,0x1FEA,0x1FEB,0x1FFA,0x1FFB,
|
||||||
|
0x1F80,0x0608, 0x1F90,0x0608, 0x1FA0,0x0608, 0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC,
|
||||||
|
0x1FCC,0x0001,0x1FC3, 0x1FD0,0x0602, 0x1FE0,0x0602, 0x1FE5,0x0001,0x1FEC, 0x1FF2,0x0001,0x1FFC,
|
||||||
|
/* Letterlike Symbols */
|
||||||
|
0x214E,0x0001,0x2132,
|
||||||
|
/* Number forms */
|
||||||
|
0x2170,0x0210, 0x2184,0x0001,0x2183,
|
||||||
|
/* Enclosed Alphanumerics */
|
||||||
|
0x24D0,0x051A, 0x2C30,0x042F,
|
||||||
|
/* Latin Extended-C */
|
||||||
|
0x2C60,0x0102, 0x2C67,0x0106, 0x2C75,0x0102,
|
||||||
|
/* Coptic */
|
||||||
|
0x2C80,0x0164,
|
||||||
|
/* Georgian Supplement */
|
||||||
|
0x2D00,0x0826,
|
||||||
|
/* Full-width */
|
||||||
|
0xFF41,0x031A,
|
||||||
|
|
||||||
|
0x0000
|
||||||
|
};
|
||||||
|
const WCHAR *p;
|
||||||
|
WCHAR bc, nc, cmd;
|
||||||
|
|
||||||
|
|
||||||
|
p = chr < 0x1000 ? cvt1 : cvt2;
|
||||||
|
for (;;) {
|
||||||
|
bc = *p++; /* Get block base */
|
||||||
|
if (!bc || chr < bc) break;
|
||||||
|
nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */
|
||||||
|
if (chr < bc + nc) { /* In the block? */
|
||||||
|
switch (cmd) {
|
||||||
|
case 0: chr = p[chr - bc]; break; /* Table conversion */
|
||||||
|
case 1: chr -= (chr - bc) & 1; break; /* Case pairs */
|
||||||
|
case 2: chr -= 16; break; /* Shift -16 */
|
||||||
|
case 3: chr -= 32; break; /* Shift -32 */
|
||||||
|
case 4: chr -= 48; break; /* Shift -48 */
|
||||||
|
case 5: chr -= 26; break; /* Shift -26 */
|
||||||
|
case 6: chr += 8; break; /* Shift +8 */
|
||||||
|
case 7: chr -= 80; break; /* Shift -80 */
|
||||||
|
case 8: chr -= 0x1C60; break; /* Shift -0x1C60 */
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!cmd) p += nc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return chr;
|
||||||
|
}
|
||||||
|
|
|
@ -3,15 +3,15 @@
|
||||||
#if _USE_LFN != 0
|
#if _USE_LFN != 0
|
||||||
|
|
||||||
#if _CODE_PAGE == 932 /* Japanese Shift_JIS */
|
#if _CODE_PAGE == 932 /* Japanese Shift_JIS */
|
||||||
#include "cc932.c"
|
#include "cc932.c.inc"
|
||||||
#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */
|
#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */
|
||||||
#include "cc936.c"
|
#include "cc936.c.inc"
|
||||||
#elif _CODE_PAGE == 949 /* Korean */
|
#elif _CODE_PAGE == 949 /* Korean */
|
||||||
#include "cc949.c"
|
#include "cc949.c.inc"
|
||||||
#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */
|
#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */
|
||||||
#include "cc950.c"
|
#include "cc950.c.inc"
|
||||||
#else /* Single Byte Character-Set */
|
#else /* Single Byte Character-Set */
|
||||||
#include "ccsbcs.c"
|
#include "ccsbcs.c.inc"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
6
components/jsmn/component.mk
Normal file
6
components/jsmn/component.mk
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#
|
||||||
|
# Component Makefile
|
||||||
|
#
|
||||||
|
|
||||||
|
COMPONENT_ADD_INCLUDEDIRS := include/
|
||||||
|
COMPONENT_SRCDIRS := src/
|
106
components/jsmn/include/jsmn.h
Normal file
106
components/jsmn/include/jsmn.h
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010 Serge A. Zaitsev
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file jsmn.h
|
||||||
|
* @brief Definition of the JSMN (Jasmine) JSON parser.
|
||||||
|
*
|
||||||
|
* For more information on JSMN:
|
||||||
|
* @see http://zserge.com/jsmn.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __JSMN_H_
|
||||||
|
#define __JSMN_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON type identifier. Basic types are:
|
||||||
|
* o Object
|
||||||
|
* o Array
|
||||||
|
* o String
|
||||||
|
* o Other primitive: number, boolean (true/false) or null
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
JSMN_UNDEFINED = 0,
|
||||||
|
JSMN_OBJECT = 1,
|
||||||
|
JSMN_ARRAY = 2,
|
||||||
|
JSMN_STRING = 3,
|
||||||
|
JSMN_PRIMITIVE = 4
|
||||||
|
} jsmntype_t;
|
||||||
|
|
||||||
|
enum jsmnerr {
|
||||||
|
/* Not enough tokens were provided */
|
||||||
|
JSMN_ERROR_NOMEM = -1,
|
||||||
|
/* Invalid character inside JSON string */
|
||||||
|
JSMN_ERROR_INVAL = -2,
|
||||||
|
/* The string is not a full JSON packet, more bytes expected */
|
||||||
|
JSMN_ERROR_PART = -3
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON token description.
|
||||||
|
* @param type type (object, array, string etc.)
|
||||||
|
* @param start start position in JSON data string
|
||||||
|
* @param end end position in JSON data string
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
jsmntype_t type;
|
||||||
|
int start;
|
||||||
|
int end;
|
||||||
|
int size;
|
||||||
|
#ifdef JSMN_PARENT_LINKS
|
||||||
|
int parent;
|
||||||
|
#endif
|
||||||
|
} jsmntok_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON parser. Contains an array of token blocks available. Also stores
|
||||||
|
* the string being parsed now and current position in that string
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
unsigned int pos; /* offset in the JSON string */
|
||||||
|
unsigned int toknext; /* next token to allocate */
|
||||||
|
int toksuper; /* superior token node, e.g parent object or array */
|
||||||
|
} jsmn_parser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create JSON parser over an array of tokens
|
||||||
|
*/
|
||||||
|
void jsmn_init(jsmn_parser *parser);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run JSON parser. It parses a JSON data string into and array of tokens, each describing
|
||||||
|
* a single JSON object.
|
||||||
|
*/
|
||||||
|
int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
|
||||||
|
jsmntok_t *tokens, unsigned int num_tokens);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __JSMN_H_ */
|
341
components/jsmn/src/jsmn.c
Normal file
341
components/jsmn/src/jsmn.c
Normal file
|
@ -0,0 +1,341 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010 Serge A. Zaitsev
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file jsmn.c
|
||||||
|
* @brief Implementation of the JSMN (Jasmine) JSON parser.
|
||||||
|
*
|
||||||
|
* For more information on JSMN:
|
||||||
|
* @see http://zserge.com/jsmn.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "jsmn.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocates a fresh unused token from the token pull.
|
||||||
|
*/
|
||||||
|
static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
|
||||||
|
jsmntok_t *tokens, size_t num_tokens) {
|
||||||
|
jsmntok_t *tok;
|
||||||
|
if (parser->toknext >= num_tokens) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
tok = &tokens[parser->toknext++];
|
||||||
|
tok->start = tok->end = -1;
|
||||||
|
tok->size = 0;
|
||||||
|
#ifdef JSMN_PARENT_LINKS
|
||||||
|
tok->parent = -1;
|
||||||
|
#endif
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills token type and boundaries.
|
||||||
|
*/
|
||||||
|
static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
|
||||||
|
int start, int end) {
|
||||||
|
token->type = type;
|
||||||
|
token->start = start;
|
||||||
|
token->end = end;
|
||||||
|
token->size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills next available token with JSON primitive.
|
||||||
|
*/
|
||||||
|
static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
|
||||||
|
size_t len, jsmntok_t *tokens, size_t num_tokens) {
|
||||||
|
jsmntok_t *token;
|
||||||
|
int start;
|
||||||
|
|
||||||
|
start = parser->pos;
|
||||||
|
|
||||||
|
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
|
||||||
|
switch (js[parser->pos]) {
|
||||||
|
#ifndef JSMN_STRICT
|
||||||
|
/* In strict mode primitive must be followed by "," or "}" or "]" */
|
||||||
|
case ':':
|
||||||
|
#endif
|
||||||
|
case '\t' : case '\r' : case '\n' : case ' ' :
|
||||||
|
case ',' : case ']' : case '}' :
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
|
||||||
|
parser->pos = start;
|
||||||
|
return JSMN_ERROR_INVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef JSMN_STRICT
|
||||||
|
/* In strict mode primitive must be followed by a comma/object/array */
|
||||||
|
parser->pos = start;
|
||||||
|
return JSMN_ERROR_PART;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
found:
|
||||||
|
if (tokens == NULL) {
|
||||||
|
parser->pos--;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
||||||
|
if (token == NULL) {
|
||||||
|
parser->pos = start;
|
||||||
|
return JSMN_ERROR_NOMEM;
|
||||||
|
}
|
||||||
|
jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
|
||||||
|
#ifdef JSMN_PARENT_LINKS
|
||||||
|
token->parent = parser->toksuper;
|
||||||
|
#endif
|
||||||
|
parser->pos--;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills next token with JSON string.
|
||||||
|
*/
|
||||||
|
static int jsmn_parse_string(jsmn_parser *parser, const char *js,
|
||||||
|
size_t len, jsmntok_t *tokens, size_t num_tokens) {
|
||||||
|
jsmntok_t *token;
|
||||||
|
|
||||||
|
int start = parser->pos;
|
||||||
|
|
||||||
|
parser->pos++;
|
||||||
|
|
||||||
|
/* Skip starting quote */
|
||||||
|
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
|
||||||
|
char c = js[parser->pos];
|
||||||
|
|
||||||
|
/* Quote: end of string */
|
||||||
|
if (c == '\"') {
|
||||||
|
if (tokens == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
||||||
|
if (token == NULL) {
|
||||||
|
parser->pos = start;
|
||||||
|
return JSMN_ERROR_NOMEM;
|
||||||
|
}
|
||||||
|
jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
|
||||||
|
#ifdef JSMN_PARENT_LINKS
|
||||||
|
token->parent = parser->toksuper;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Backslash: Quoted symbol expected */
|
||||||
|
if (c == '\\' && parser->pos + 1 < len) {
|
||||||
|
int i;
|
||||||
|
parser->pos++;
|
||||||
|
switch (js[parser->pos]) {
|
||||||
|
/* Allowed escaped symbols */
|
||||||
|
case '\"': case '/' : case '\\' : case 'b' :
|
||||||
|
case 'f' : case 'r' : case 'n' : case 't' :
|
||||||
|
break;
|
||||||
|
/* Allows escaped symbol \uXXXX */
|
||||||
|
case 'u':
|
||||||
|
parser->pos++;
|
||||||
|
for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
|
||||||
|
/* If it isn't a hex character we have an error */
|
||||||
|
if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
|
||||||
|
(js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
|
||||||
|
(js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
|
||||||
|
parser->pos = start;
|
||||||
|
return JSMN_ERROR_INVAL;
|
||||||
|
}
|
||||||
|
parser->pos++;
|
||||||
|
}
|
||||||
|
parser->pos--;
|
||||||
|
break;
|
||||||
|
/* Unexpected symbol */
|
||||||
|
default:
|
||||||
|
parser->pos = start;
|
||||||
|
return JSMN_ERROR_INVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parser->pos = start;
|
||||||
|
return JSMN_ERROR_PART;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse JSON string and fill tokens.
|
||||||
|
*/
|
||||||
|
int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
|
||||||
|
jsmntok_t *tokens, unsigned int num_tokens) {
|
||||||
|
int r;
|
||||||
|
int i;
|
||||||
|
jsmntok_t *token;
|
||||||
|
int count = parser->toknext;
|
||||||
|
|
||||||
|
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
|
||||||
|
char c;
|
||||||
|
jsmntype_t type;
|
||||||
|
|
||||||
|
c = js[parser->pos];
|
||||||
|
switch (c) {
|
||||||
|
case '{': case '[':
|
||||||
|
count++;
|
||||||
|
if (tokens == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
||||||
|
if (token == NULL)
|
||||||
|
return JSMN_ERROR_NOMEM;
|
||||||
|
if (parser->toksuper != -1) {
|
||||||
|
tokens[parser->toksuper].size++;
|
||||||
|
#ifdef JSMN_PARENT_LINKS
|
||||||
|
token->parent = parser->toksuper;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
|
||||||
|
token->start = parser->pos;
|
||||||
|
parser->toksuper = parser->toknext - 1;
|
||||||
|
break;
|
||||||
|
case '}': case ']':
|
||||||
|
if (tokens == NULL)
|
||||||
|
break;
|
||||||
|
type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
|
||||||
|
#ifdef JSMN_PARENT_LINKS
|
||||||
|
if (parser->toknext < 1) {
|
||||||
|
return JSMN_ERROR_INVAL;
|
||||||
|
}
|
||||||
|
token = &tokens[parser->toknext - 1];
|
||||||
|
for (;;) {
|
||||||
|
if (token->start != -1 && token->end == -1) {
|
||||||
|
if (token->type != type) {
|
||||||
|
return JSMN_ERROR_INVAL;
|
||||||
|
}
|
||||||
|
token->end = parser->pos + 1;
|
||||||
|
parser->toksuper = token->parent;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (token->parent == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
token = &tokens[token->parent];
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
for (i = parser->toknext - 1; i >= 0; i--) {
|
||||||
|
token = &tokens[i];
|
||||||
|
if (token->start != -1 && token->end == -1) {
|
||||||
|
if (token->type != type) {
|
||||||
|
return JSMN_ERROR_INVAL;
|
||||||
|
}
|
||||||
|
parser->toksuper = -1;
|
||||||
|
token->end = parser->pos + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Error if unmatched closing bracket */
|
||||||
|
if (i == -1) return JSMN_ERROR_INVAL;
|
||||||
|
for (; i >= 0; i--) {
|
||||||
|
token = &tokens[i];
|
||||||
|
if (token->start != -1 && token->end == -1) {
|
||||||
|
parser->toksuper = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case '\"':
|
||||||
|
r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
|
||||||
|
if (r < 0) return r;
|
||||||
|
count++;
|
||||||
|
if (parser->toksuper != -1 && tokens != NULL)
|
||||||
|
tokens[parser->toksuper].size++;
|
||||||
|
break;
|
||||||
|
case '\t' : case '\r' : case '\n' : case ' ':
|
||||||
|
break;
|
||||||
|
case ':':
|
||||||
|
parser->toksuper = parser->toknext - 1;
|
||||||
|
break;
|
||||||
|
case ',':
|
||||||
|
if (tokens != NULL && parser->toksuper != -1 &&
|
||||||
|
tokens[parser->toksuper].type != JSMN_ARRAY &&
|
||||||
|
tokens[parser->toksuper].type != JSMN_OBJECT) {
|
||||||
|
#ifdef JSMN_PARENT_LINKS
|
||||||
|
parser->toksuper = tokens[parser->toksuper].parent;
|
||||||
|
#else
|
||||||
|
for (i = parser->toknext - 1; i >= 0; i--) {
|
||||||
|
if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
|
||||||
|
if (tokens[i].start != -1 && tokens[i].end == -1) {
|
||||||
|
parser->toksuper = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#ifdef JSMN_STRICT
|
||||||
|
/* In strict mode primitives are: numbers and booleans */
|
||||||
|
case '-': case '0': case '1' : case '2': case '3' : case '4':
|
||||||
|
case '5': case '6': case '7' : case '8': case '9':
|
||||||
|
case 't': case 'f': case 'n' :
|
||||||
|
/* And they must not be keys of the object */
|
||||||
|
if (tokens != NULL && parser->toksuper != -1) {
|
||||||
|
jsmntok_t *t = &tokens[parser->toksuper];
|
||||||
|
if (t->type == JSMN_OBJECT ||
|
||||||
|
(t->type == JSMN_STRING && t->size != 0)) {
|
||||||
|
return JSMN_ERROR_INVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/* In non-strict mode every unquoted value is a primitive */
|
||||||
|
default:
|
||||||
|
#endif
|
||||||
|
r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
|
||||||
|
if (r < 0) return r;
|
||||||
|
count++;
|
||||||
|
if (parser->toksuper != -1 && tokens != NULL)
|
||||||
|
tokens[parser->toksuper].size++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
#ifdef JSMN_STRICT
|
||||||
|
/* Unexpected char in strict mode */
|
||||||
|
default:
|
||||||
|
return JSMN_ERROR_INVAL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tokens != NULL) {
|
||||||
|
for (i = parser->toknext - 1; i >= 0; i--) {
|
||||||
|
/* Unmatched opened object or array */
|
||||||
|
if (tokens[i].start != -1 && tokens[i].end == -1) {
|
||||||
|
return JSMN_ERROR_PART;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new parser based over a given buffer with an array of tokens
|
||||||
|
* available.
|
||||||
|
*/
|
||||||
|
void jsmn_init(jsmn_parser *parser) {
|
||||||
|
parser->pos = 0;
|
||||||
|
parser->toknext = 0;
|
||||||
|
parser->toksuper = -1;
|
||||||
|
}
|
||||||
|
|
|
@ -24,15 +24,12 @@ config MBEDTLS_DEBUG
|
||||||
bool "Enable mbedTLS debugging"
|
bool "Enable mbedTLS debugging"
|
||||||
default n
|
default n
|
||||||
help
|
help
|
||||||
Enable mbedTLS debugging functions.
|
Enable mbedTLS debugging functions at compile time.
|
||||||
|
|
||||||
If this option is enabled, use the mbedtls_debug_set_threshold()
|
If this option is enabled, you can include
|
||||||
and mbedtls_ssl_conf_dbg() functions to obtain debugging output
|
"mbedtls/esp_debug.h" and call mbedtls_esp_enable_debug_log()
|
||||||
from mbedTLS.
|
at runtime in order to enable mbedTLS debug output via the ESP
|
||||||
|
log mechanism.
|
||||||
Note thatm mbedTLS debugging is not related to the ESP logging
|
|
||||||
functionality. See the "https_request_main" example for a
|
|
||||||
sample function which connects the two together.
|
|
||||||
|
|
||||||
config MBEDTLS_HARDWARE_AES
|
config MBEDTLS_HARDWARE_AES
|
||||||
bool "Enable hardware AES acceleration"
|
bool "Enable hardware AES acceleration"
|
||||||
|
|
|
@ -782,7 +782,7 @@
|
||||||
*
|
*
|
||||||
* Enable functions that use the filesystem.
|
* Enable functions that use the filesystem.
|
||||||
*/
|
*/
|
||||||
//#define MBEDTLS_FS_IO
|
#define MBEDTLS_FS_IO
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \def MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
|
* \def MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
|
||||||
|
|
45
components/mbedtls/port/include/mbedtls/esp_debug.h
Normal file
45
components/mbedtls/port/include/mbedtls/esp_debug.h
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#ifdef CONFIG_MBEDTLS_DEBUG
|
||||||
|
|
||||||
|
/** @brief Enable mbedTLS debug logging via the esp_log mechanism.
|
||||||
|
*
|
||||||
|
* mbedTLS internal debugging is filtered from a specified mbedTLS
|
||||||
|
* threshold level to esp_log level at runtime:
|
||||||
|
*
|
||||||
|
* - 1 - Warning
|
||||||
|
* - 2 - Info
|
||||||
|
* - 3 - Debug
|
||||||
|
* - 4 - Verbose
|
||||||
|
*
|
||||||
|
* (Note that mbedTLS debug thresholds are not always consistently used.)
|
||||||
|
*
|
||||||
|
* This function will set the esp log level for "mbedtls" to the specified mbedTLS
|
||||||
|
* threshold level that matches. However, the overall max ESP log level must be set high
|
||||||
|
* enough in menuconfig, or some messages may be filtered at compile time.
|
||||||
|
*
|
||||||
|
* @param conf mbedtls_ssl_config structure
|
||||||
|
* @param mbedTLS debug threshold, 0-4. Messages are filtered at runtime.
|
||||||
|
*/
|
||||||
|
void mbedtls_esp_enable_debug_log(mbedtls_ssl_config *conf, int threshold);
|
||||||
|
|
||||||
|
/** @brief Disable mbedTLS debug logging via the esp_log mechanism.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void mbedtls_esp_disable_debug_log(mbedtls_ssl_config *conf);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
86
components/mbedtls/port/mbedtls_debug.c
Normal file
86
components/mbedtls/port/mbedtls_debug.c
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <strings.h>
|
||||||
|
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "mbedtls/platform.h"
|
||||||
|
#include "mbedtls/debug.h"
|
||||||
|
#include "mbedtls/ssl.h"
|
||||||
|
#include "mbedtls/esp_debug.h"
|
||||||
|
|
||||||
|
static const char *TAG = "mbedtls";
|
||||||
|
|
||||||
|
static void mbedtls_esp_debug(void *ctx, int level,
|
||||||
|
const char *file, int line,
|
||||||
|
const char *str);
|
||||||
|
|
||||||
|
void mbedtls_esp_enable_debug_log(mbedtls_ssl_config *conf, int threshold)
|
||||||
|
{
|
||||||
|
mbedtls_debug_set_threshold(threshold);
|
||||||
|
mbedtls_ssl_conf_dbg(conf, mbedtls_esp_debug, NULL);
|
||||||
|
esp_log_level_t level = ESP_LOG_NONE;
|
||||||
|
switch(threshold) {
|
||||||
|
case 1:
|
||||||
|
level = ESP_LOG_WARN;
|
||||||
|
case 2:
|
||||||
|
level = ESP_LOG_INFO;
|
||||||
|
case 3:
|
||||||
|
level = ESP_LOG_DEBUG;
|
||||||
|
case 4:
|
||||||
|
level = ESP_LOG_VERBOSE;
|
||||||
|
}
|
||||||
|
esp_log_level_set(TAG, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mbedtls_esp_disable_debug_log(mbedtls_ssl_config *conf)
|
||||||
|
{
|
||||||
|
mbedtls_ssl_conf_dbg(conf, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Default mbedtls debug function that translates mbedTLS debug output
|
||||||
|
to ESP_LOGx debug output.
|
||||||
|
*/
|
||||||
|
static void mbedtls_esp_debug(void *ctx, int level,
|
||||||
|
const char *file, int line,
|
||||||
|
const char *str)
|
||||||
|
{
|
||||||
|
char *file_sep;
|
||||||
|
|
||||||
|
/* Shorten 'file' from the whole file path to just the filename
|
||||||
|
|
||||||
|
This is a bit wasteful because the macros are compiled in with
|
||||||
|
the full _FILE_ path in each case.
|
||||||
|
*/
|
||||||
|
file_sep = rindex(file, '/');
|
||||||
|
if(file_sep)
|
||||||
|
file = file_sep+1;
|
||||||
|
|
||||||
|
switch(level) {
|
||||||
|
case 1:
|
||||||
|
ESP_LOGW(TAG, "%s:%d %s", file, line, str);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
ESP_LOGI(TAG, "%s:%d %s", file, line, str);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
ESP_LOGD(TAG, "%s:%d %s", file, line, str);
|
||||||
|
case 4:
|
||||||
|
ESP_LOGV(TAG, "%s:%d %s", file, line, str);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ESP_LOGE(TAG, "Unexpected log level %d: %s", level, str);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
|
@ -203,6 +203,8 @@ int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char
|
||||||
*/
|
*/
|
||||||
static int net_would_block( const mbedtls_net_context *ctx )
|
static int net_would_block( const mbedtls_net_context *ctx )
|
||||||
{
|
{
|
||||||
|
int error = mbedtls_net_errno(ctx->fd);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Never return 'WOULD BLOCK' on a non-blocking socket
|
* Never return 'WOULD BLOCK' on a non-blocking socket
|
||||||
*/
|
*/
|
||||||
|
@ -210,8 +212,6 @@ static int net_would_block( const mbedtls_net_context *ctx )
|
||||||
return ( 0 );
|
return ( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
int error = mbedtls_net_errno(ctx->fd);
|
|
||||||
|
|
||||||
switch ( error ) {
|
switch ( error ) {
|
||||||
#if defined EAGAIN
|
#if defined EAGAIN
|
||||||
case EAGAIN:
|
case EAGAIN:
|
||||||
|
|
|
@ -491,7 +491,7 @@ static const uint8_t * _mdns_read_fqdn(const uint8_t * packet, const uint8_t * s
|
||||||
&& (strcmp(buf, MDNS_DEFAULT_DOMAIN) != 0)
|
&& (strcmp(buf, MDNS_DEFAULT_DOMAIN) != 0)
|
||||||
&& (strcmp(buf, "ip6") != 0)
|
&& (strcmp(buf, "ip6") != 0)
|
||||||
&& (strcmp(buf, "in-addr") != 0)) {
|
&& (strcmp(buf, "in-addr") != 0)) {
|
||||||
sprintf((char*)name, "%s.%s", name->host, buf);
|
snprintf((char*)name, MDNS_NAME_BUF_LEN, "%s.%s", name->host, buf);
|
||||||
} else if (strcmp(buf, MDNS_SUB_STR) == 0) {
|
} else if (strcmp(buf, MDNS_SUB_STR) == 0) {
|
||||||
name->sub = 1;
|
name->sub = 1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -499,7 +499,7 @@ static const uint8_t * _mdns_read_fqdn(const uint8_t * packet, const uint8_t * s
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
size_t address = (((uint16_t)len & 0x3F) << 8) | start[index++];
|
size_t address = (((uint16_t)len & 0x3F) << 8) | start[index++];
|
||||||
if ((packet + address) > start) {
|
if ((packet + address) >= start) {
|
||||||
//reference address can not be after where we are
|
//reference address can not be after where we are
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1182,13 +1182,13 @@ static mdns_service_t * _mdns_create_service(const char * service, const char *
|
||||||
s->txt = NULL;
|
s->txt = NULL;
|
||||||
s->port = port;
|
s->port = port;
|
||||||
|
|
||||||
s->service = strdup(service);
|
s->service = strndup(service, MDNS_NAME_BUF_LEN - 1);
|
||||||
if (!s->service) {
|
if (!s->service) {
|
||||||
free(s);
|
free(s);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->proto = strdup(proto);
|
s->proto = strndup(proto, MDNS_NAME_BUF_LEN - 1);
|
||||||
if (!s->proto) {
|
if (!s->proto) {
|
||||||
free((char *)s->service);
|
free((char *)s->service);
|
||||||
free(s);
|
free(s);
|
||||||
|
@ -1341,7 +1341,7 @@ static void _mdns_parse_packet(mdns_server_t * server, const uint8_t * data, siz
|
||||||
(strcmp(name->proto, server->search.proto) != 0)) {
|
(strcmp(name->proto, server->search.proto) != 0)) {
|
||||||
continue;//not searching for service or wrong service/proto
|
continue;//not searching for service or wrong service/proto
|
||||||
}
|
}
|
||||||
sprintf(answer->instance, "%s", name->host);
|
strlcpy(answer->instance, name->host, MDNS_NAME_BUF_LEN);
|
||||||
} else if (type == MDNS_TYPE_SRV) {
|
} else if (type == MDNS_TYPE_SRV) {
|
||||||
if (server->search.host[0] ||
|
if (server->search.host[0] ||
|
||||||
(strcmp(name->service, server->search.service) != 0) ||
|
(strcmp(name->service, server->search.service) != 0) ||
|
||||||
|
@ -1353,7 +1353,7 @@ static void _mdns_parse_packet(mdns_server_t * server, const uint8_t * data, siz
|
||||||
continue;//instance name is not the same as the one in the PTR record
|
continue;//instance name is not the same as the one in the PTR record
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sprintf(answer->instance, "%s", name->host);
|
strlcpy(answer->instance, name->host, MDNS_NAME_BUF_LEN);
|
||||||
}
|
}
|
||||||
//parse record value
|
//parse record value
|
||||||
if (!_mdns_parse_fqdn(data, data_ptr + MDNS_SRV_FQDN_OFFSET, name)) {
|
if (!_mdns_parse_fqdn(data, data_ptr + MDNS_SRV_FQDN_OFFSET, name)) {
|
||||||
|
@ -1367,15 +1367,19 @@ static void _mdns_parse_packet(mdns_server_t * server, const uint8_t * data, siz
|
||||||
if (answer->host[0]) {
|
if (answer->host[0]) {
|
||||||
if (strcmp(answer->host, name->host) != 0) {
|
if (strcmp(answer->host, name->host) != 0) {
|
||||||
answer->addr = 0;
|
answer->addr = 0;
|
||||||
sprintf(answer->host, "%s", name->host);
|
strlcpy(answer->host, name->host, MDNS_NAME_BUF_LEN);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sprintf(answer->host, "%s", name->host);
|
strlcpy(answer->host, name->host, MDNS_NAME_BUF_LEN);
|
||||||
}
|
}
|
||||||
} else if (type == MDNS_TYPE_TXT) {
|
} else if (type == MDNS_TYPE_TXT) {
|
||||||
uint16_t i=0,b=0, y;
|
uint16_t i=0,b=0, y;
|
||||||
while(i < data_len) {
|
while(i < data_len) {
|
||||||
uint8_t partLen = data_ptr[i++];
|
uint8_t partLen = data_ptr[i++];
|
||||||
|
//check if partLen will fit in the buffer
|
||||||
|
if (partLen > (MDNS_TXT_MAX_LEN - b - 1)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
for(y=0; y<partLen; y++) {
|
for(y=0; y<partLen; y++) {
|
||||||
char d = data_ptr[i++];
|
char d = data_ptr[i++];
|
||||||
answer->txt[b++] = d;
|
answer->txt[b++] = d;
|
||||||
|
@ -1391,7 +1395,7 @@ static void _mdns_parse_packet(mdns_server_t * server, const uint8_t * data, siz
|
||||||
continue;//wrong host
|
continue;//wrong host
|
||||||
}
|
}
|
||||||
} else if (!answer->ptr) {
|
} else if (!answer->ptr) {
|
||||||
sprintf(answer->host, "%s", name->host);
|
strlcpy(answer->host, name->host, MDNS_NAME_BUF_LEN);
|
||||||
} else if (strcmp(answer->host, name->host) != 0) {
|
} else if (strcmp(answer->host, name->host) != 0) {
|
||||||
continue;//wrong host
|
continue;//wrong host
|
||||||
}
|
}
|
||||||
|
@ -1402,7 +1406,7 @@ static void _mdns_parse_packet(mdns_server_t * server, const uint8_t * data, siz
|
||||||
continue;//wrong host
|
continue;//wrong host
|
||||||
}
|
}
|
||||||
} else if (!answer->ptr) {
|
} else if (!answer->ptr) {
|
||||||
sprintf(answer->host, "%s", name->host);
|
strlcpy(answer->host, name->host, MDNS_NAME_BUF_LEN);
|
||||||
} else if (strcmp(answer->host, name->host) != 0) {
|
} else if (strcmp(answer->host, name->host) != 0) {
|
||||||
continue;//wrong host
|
continue;//wrong host
|
||||||
}
|
}
|
||||||
|
@ -1534,6 +1538,9 @@ esp_err_t mdns_set_hostname(mdns_server_t * server, const char * hostname)
|
||||||
if (!server) {
|
if (!server) {
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
if (strlen(hostname) > (MDNS_NAME_BUF_LEN - 1)) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
MDNS_MUTEX_LOCK();
|
MDNS_MUTEX_LOCK();
|
||||||
free((char*)server->hostname);
|
free((char*)server->hostname);
|
||||||
server->hostname = (char *)malloc(strlen(hostname)+1);
|
server->hostname = (char *)malloc(strlen(hostname)+1);
|
||||||
|
@ -1541,7 +1548,7 @@ esp_err_t mdns_set_hostname(mdns_server_t * server, const char * hostname)
|
||||||
MDNS_MUTEX_UNLOCK();
|
MDNS_MUTEX_UNLOCK();
|
||||||
return ESP_ERR_NO_MEM;
|
return ESP_ERR_NO_MEM;
|
||||||
}
|
}
|
||||||
sprintf((char *)server->hostname, "%s", hostname);
|
strlcpy((char *)server->hostname, hostname, MDNS_NAME_BUF_LEN);
|
||||||
MDNS_MUTEX_UNLOCK();
|
MDNS_MUTEX_UNLOCK();
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
@ -1551,6 +1558,9 @@ esp_err_t mdns_set_instance(mdns_server_t * server, const char * instance)
|
||||||
if (!server) {
|
if (!server) {
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
if (strlen(instance) > (MDNS_NAME_BUF_LEN - 1)) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
MDNS_MUTEX_LOCK();
|
MDNS_MUTEX_LOCK();
|
||||||
free((char*)server->instance);
|
free((char*)server->instance);
|
||||||
server->instance = (char *)malloc(strlen(instance)+1);
|
server->instance = (char *)malloc(strlen(instance)+1);
|
||||||
|
@ -1558,7 +1568,7 @@ esp_err_t mdns_set_instance(mdns_server_t * server, const char * instance)
|
||||||
MDNS_MUTEX_UNLOCK();
|
MDNS_MUTEX_UNLOCK();
|
||||||
return ESP_ERR_NO_MEM;
|
return ESP_ERR_NO_MEM;
|
||||||
}
|
}
|
||||||
sprintf((char *)server->instance, "%s", instance);
|
strlcpy((char *)server->instance, instance, MDNS_NAME_BUF_LEN);
|
||||||
MDNS_MUTEX_UNLOCK();
|
MDNS_MUTEX_UNLOCK();
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
@ -1655,6 +1665,9 @@ esp_err_t mdns_service_instance_set(mdns_server_t * server, const char * service
|
||||||
if (!server || !server->services || !service || !proto) {
|
if (!server || !server->services || !service || !proto) {
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
if (strlen(instance) > (MDNS_NAME_BUF_LEN - 1)) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
mdns_srv_item_t * s = _mdns_get_service_item(server, service, proto);
|
mdns_srv_item_t * s = _mdns_get_service_item(server, service, proto);
|
||||||
if (!s) {
|
if (!s) {
|
||||||
return ESP_ERR_NOT_FOUND;
|
return ESP_ERR_NOT_FOUND;
|
||||||
|
@ -1741,10 +1754,10 @@ uint32_t mdns_query(mdns_server_t * server, const char * service, const char * p
|
||||||
mdns_result_free(server);
|
mdns_result_free(server);
|
||||||
if (proto) {
|
if (proto) {
|
||||||
server->search.host[0] = 0;
|
server->search.host[0] = 0;
|
||||||
snprintf(server->search.service, MDNS_NAME_MAX_LEN, "%s", service);
|
strlcpy(server->search.service, service, MDNS_NAME_BUF_LEN);
|
||||||
snprintf(server->search.proto, MDNS_NAME_MAX_LEN, "%s", proto);
|
strlcpy(server->search.proto, proto, MDNS_NAME_BUF_LEN);
|
||||||
} else {
|
} else {
|
||||||
snprintf(server->search.host, MDNS_NAME_MAX_LEN, "%s", service);
|
strlcpy(server->search.host, service, MDNS_NAME_BUF_LEN);
|
||||||
server->search.service[0] = 0;
|
server->search.service[0] = 0;
|
||||||
server->search.proto[0] = 0;
|
server->search.proto[0] = 0;
|
||||||
qtype = MDNS_TYPE_A;
|
qtype = MDNS_TYPE_A;
|
||||||
|
|
|
@ -26,6 +26,8 @@ Additional third party copyrighted code is included under the following licenses
|
||||||
|
|
||||||
* `FreeBSD net80211`_ Copyright (c) 2004-2008 Sam Leffler, Errno Consulting and licensed under the BSD license.
|
* `FreeBSD net80211`_ Copyright (c) 2004-2008 Sam Leffler, Errno Consulting and licensed under the BSD license.
|
||||||
|
|
||||||
|
* `JSMN`_ JSON Parser (components/jsmn) Copyright (c) 2010 Serge A. Zaitsev and licensed under the MIT license.
|
||||||
|
|
||||||
Where source code headers specify Copyright & License information, this information takes precedence over the summaries made here.
|
Where source code headers specify Copyright & License information, this information takes precedence over the summaries made here.
|
||||||
|
|
||||||
ROM Source Code Copyrights
|
ROM Source Code Copyrights
|
||||||
|
@ -103,3 +105,4 @@ Copyright (C) 2011, ChaN, all right reserved.
|
||||||
.. _wpa_supplicant: http://w1.fi/wpa_supplicant/
|
.. _wpa_supplicant: http://w1.fi/wpa_supplicant/
|
||||||
.. _FreeBSD net80211: https://github.com/freebsd/freebsd/tree/master/sys/net80211
|
.. _FreeBSD net80211: https://github.com/freebsd/freebsd/tree/master/sys/net80211
|
||||||
.. _TJpgDec: http://elm-chan.org/fsw/tjpgd/00index.html
|
.. _TJpgDec: http://elm-chan.org/fsw/tjpgd/00index.html
|
||||||
|
.. _JSMN: http://zserge.com/jsmn.html
|
||||||
|
|
113
docs/idf-monitor.rst
Normal file
113
docs/idf-monitor.rst
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
IDF Monitor
|
||||||
|
***********
|
||||||
|
|
||||||
|
The idf_monitor tool is a Python program which runs when the ``make monitor`` target is invoked in IDF.
|
||||||
|
|
||||||
|
It is mainly a serial terminal program which relays serial data to and from the target device's serial port, but it has some other IDF-specific xfeatures.
|
||||||
|
|
||||||
|
Interacting With idf_monitor
|
||||||
|
============================
|
||||||
|
|
||||||
|
- ``Ctrl-]`` will exit the monitor.
|
||||||
|
- ``Ctrl-T Ctrl-H`` will display a help menu with all other keyboard shortcuts.
|
||||||
|
- Any other key apart from ``Ctrl-]`` and ``Ctrl-T`` is sent through the serial port.
|
||||||
|
|
||||||
|
Automatically Decoding Addresses
|
||||||
|
================================
|
||||||
|
|
||||||
|
Any time esp-idf prints a hexadecimal code address of the form ``0x4_______``, idf_monitor will use addr2line_ to look up the source code location and function name.
|
||||||
|
|
||||||
|
When an esp-idf app crashes and panics a register dump and backtrace such as this is produced::
|
||||||
|
|
||||||
|
Guru Meditation Error of type StoreProhibited occurred on core 0. Exception was unhandled.
|
||||||
|
Register dump:
|
||||||
|
PC : 0x400f360d PS : 0x00060330 A0 : 0x800dbf56 A1 : 0x3ffb7e00
|
||||||
|
A2 : 0x3ffb136c A3 : 0x00000005 A4 : 0x00000000 A5 : 0x00000000
|
||||||
|
A6 : 0x00000000 A7 : 0x00000080 A8 : 0x00000000 A9 : 0x3ffb7dd0
|
||||||
|
A10 : 0x00000003 A11 : 0x00060f23 A12 : 0x00060f20 A13 : 0x3ffba6d0
|
||||||
|
A14 : 0x00000047 A15 : 0x0000000f SAR : 0x00000019 EXCCAUSE: 0x0000001d
|
||||||
|
EXCVADDR: 0x00000000 LBEG : 0x4000c46c LEND : 0x4000c477 LCOUNT : 0x00000000
|
||||||
|
|
||||||
|
Backtrace: 0x400f360d:0x3ffb7e00 0x400dbf56:0x3ffb7e20 0x400dbf5e:0x3ffb7e40 0x400dbf82:0x3ffb7e60 0x400d071d:0x3ffb7e90
|
||||||
|
|
||||||
|
idf_monitor will augment the dump::
|
||||||
|
|
||||||
|
Guru Meditation Error of type StoreProhibited occurred on core 0. Exception was unhandled.
|
||||||
|
Register dump:
|
||||||
|
PC : 0x400f360d PS : 0x00060330 A0 : 0x800dbf56 A1 : 0x3ffb7e00
|
||||||
|
0x400f360d: do_something_to_crash at /home/gus/esp/32/idf/examples/get-started/hello_world/main/./hello_world_main.c:57
|
||||||
|
(inlined by) inner_dont_crash at /home/gus/esp/32/idf/examples/get-started/hello_world/main/./hello_world_main.c:52
|
||||||
|
A2 : 0x3ffb136c A3 : 0x00000005 A4 : 0x00000000 A5 : 0x00000000
|
||||||
|
A6 : 0x00000000 A7 : 0x00000080 A8 : 0x00000000 A9 : 0x3ffb7dd0
|
||||||
|
A10 : 0x00000003 A11 : 0x00060f23 A12 : 0x00060f20 A13 : 0x3ffba6d0
|
||||||
|
A14 : 0x00000047 A15 : 0x0000000f SAR : 0x00000019 EXCCAUSE: 0x0000001d
|
||||||
|
EXCVADDR: 0x00000000 LBEG : 0x4000c46c LEND : 0x4000c477 LCOUNT : 0x00000000
|
||||||
|
|
||||||
|
Backtrace: 0x400f360d:0x3ffb7e00 0x400dbf56:0x3ffb7e20 0x400dbf5e:0x3ffb7e40 0x400dbf82:0x3ffb7e60 0x400d071d:0x3ffb7e90
|
||||||
|
0x400f360d: do_something_to_crash at /home/gus/esp/32/idf/examples/get-started/hello_world/main/./hello_world_main.c:57
|
||||||
|
(inlined by) inner_dont_crash at /home/gus/esp/32/idf/examples/get-started/hello_world/main/./hello_world_main.c:52
|
||||||
|
0x400dbf56: still_dont_crash at /home/gus/esp/32/idf/examples/get-started/hello_world/main/./hello_world_main.c:47
|
||||||
|
0x400dbf5e: dont_crash at /home/gus/esp/32/idf/examples/get-started/hello_world/main/./hello_world_main.c:42
|
||||||
|
0x400dbf82: app_main at /home/gus/esp/32/idf/examples/get-started/hello_world/main/./hello_world_main.c:33
|
||||||
|
0x400d071d: main_task at /home/gus/esp/32/idf/components/esp32/./cpu_start.c:254
|
||||||
|
|
||||||
|
Behind the scenes, the command idf_monitor runs to decode each address is::
|
||||||
|
|
||||||
|
xtensa-esp32-elf-addr2line -pfia -e build/PROJECT.elf ADDRESS
|
||||||
|
|
||||||
|
|
||||||
|
Launch GDB for GDBStub
|
||||||
|
======================
|
||||||
|
|
||||||
|
By default, if an esp-idf app crashes then the panic handler prints registers and a stack dump as shown above, and then resets.
|
||||||
|
|
||||||
|
Optionally, the panic handler can be configured to run a serial "gdb stub" which can communicate with a gdb_ debugger program and allow memory to be read, variables and stack frames examined, etc. This is not as versatile as JTAG debugging, but no special hardware is required.
|
||||||
|
|
||||||
|
To enable the gdbstub, run ``make menuconfig`` and navigate to ``Component config`` -> ``ESP32-specific`` -> ``Panic handler behaviour``, then set the value to ``Invoke GDBStub``.
|
||||||
|
|
||||||
|
If this option is enabled and idf_monitor sees the gdb stub has loaded, it will automatically pause serial monitoring and run GDB with the correct arguments. After GDB exits, the board will be reset via the RTS serial line (if this is connected.)
|
||||||
|
|
||||||
|
Behind the scenes, the command idf_monitor runs is::
|
||||||
|
|
||||||
|
xtensa-esp32-elf-gdb -ex "set serial baud BAUD" -ex "target remote PORT" -ex interrupt build/PROJECT.elf
|
||||||
|
|
||||||
|
|
||||||
|
Quick Compile and Flash
|
||||||
|
=======================
|
||||||
|
|
||||||
|
The keyboard shortcut ``Ctrl-T Ctrl-F`` will pause idf_monitor, run the ``make flash`` target, then resume idf_monitor. Any changed source files will be recompiled before re-flashing.
|
||||||
|
|
||||||
|
The keyboard shortcut ``Ctrl-T Ctrl-A`` will pause idf-monitor, run the ``make app-flash`` target, then resume idf_monitor. This is similar to ``make flash``, but only the main app is compiled and reflashed.
|
||||||
|
|
||||||
|
|
||||||
|
Quick Reset
|
||||||
|
===========
|
||||||
|
|
||||||
|
The keyboard shortcut ``Ctrl-T Ctrl-R`` will reset the target board via the RTS line (if it is connected.)
|
||||||
|
|
||||||
|
|
||||||
|
Simple Monitor
|
||||||
|
==============
|
||||||
|
|
||||||
|
Earlier versions of ESP-IDF used the pySerial_ command line program miniterm_ as a serial console program.
|
||||||
|
|
||||||
|
This program can still be run, via ``make simple_monitor``.
|
||||||
|
|
||||||
|
idf_monitor is based on miniterm and shares the same basic keyboard shortcuts.
|
||||||
|
|
||||||
|
|
||||||
|
Known Issues with idf_monitor
|
||||||
|
=============================
|
||||||
|
|
||||||
|
Issues Observed on Windows
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
- Arrow keys and some other special keys in gdb don't work, due to Windows Console limitations.
|
||||||
|
- Occasionally when "make" exits, it may stall for up to 30 seconds before idf_monitor resumes.
|
||||||
|
- Occasionally when "gdb" is run, it may stall for a short time before it begins communicating with the gdbstub.
|
||||||
|
|
||||||
|
|
||||||
|
.. _addr2line: https://sourceware.org/binutils/docs/binutils/addr2line.html
|
||||||
|
.. _gdb: https://sourceware.org/gdb/download/onlinedocs/
|
||||||
|
.. _pySerial: https://github.com/pyserial/pyserial
|
||||||
|
.. _miniterm: http://pyserial.readthedocs.org/en/latest/tools.html#module-serial.tools.miniterm
|
|
@ -22,6 +22,7 @@ Contents:
|
||||||
|
|
||||||
Make <make-project>
|
Make <make-project>
|
||||||
Eclipse IDE <eclipse-setup>
|
Eclipse IDE <eclipse-setup>
|
||||||
|
IDF Monitor <idf-monitor>
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:caption: What Else?
|
:caption: What Else?
|
||||||
|
|
131
examples/protocols/aws_iot/README.md
Normal file
131
examples/protocols/aws_iot/README.md
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
# Amazon Web Services IoT Examples
|
||||||
|
|
||||||
|
These examples are adaptations of some of the [AWS IoT C SDK](https://github.com/aws/aws-iot-device-sdk-embedded-C) examples.
|
||||||
|
|
||||||
|
The provisioning/configuration steps for these examples are the same, and are given in this README.
|
||||||
|
|
||||||
|
This README also contains some troubleshooting information for common problems found when connecting to AWS IoT.
|
||||||
|
|
||||||
|
# Provisioning/Configuration
|
||||||
|
|
||||||
|
There are some additional steps that need to be run before you can build this example.
|
||||||
|
|
||||||
|
The [Getting Started section of the AWS IoT Developer Guide](http://docs.aws.amazon.com/iot/latest/developerguide/iot-gs.html) lays out the steps to get started with AWS IoT.
|
||||||
|
|
||||||
|
To build and use this example, follow all the AWS IoT Getting Started steps from the beginning ("Sign in to the AWS Iot Console") up until "Configuring Your Device". For configuring the device, these are the steps:
|
||||||
|
|
||||||
|
## Configuring Your Device
|
||||||
|
|
||||||
|
### Installing Private Key & Certificate
|
||||||
|
|
||||||
|
As part of creating a device certificate, you downloaded a Private Key (`xxx-private.pem.key`) and a Certificate file (`xxx-certificate.pem.crt`). These keys need to be loaded by the ESP32 to identify itself.
|
||||||
|
|
||||||
|
There are currently two options for how to load the key & cert.
|
||||||
|
|
||||||
|
* Embed the files into the app binary (default)
|
||||||
|
* Load the files from SD card
|
||||||
|
|
||||||
|
### Option 1: Embedded Key & Cert into App Binary
|
||||||
|
|
||||||
|
Copy the `.pem.key` and `.pem.crt` files to the `main/certs` subdirectory of the example. Rename them by removing the device-specific prefix - the new names are `private.pem.key` and `certificate.pem.crt`.
|
||||||
|
|
||||||
|
As these files are bound to your AWS IoT account, take care not to accidentally commit them to public source control. In a commercial IoT device these files would be flashed to the device via a provisioning step, but for these examples they are compiled in.
|
||||||
|
|
||||||
|
### Option 2: Loading Key & Cert from SD Card
|
||||||
|
|
||||||
|
The alternative to embedding the key and certificate is to load them from a FAT filesystem on an SD card.
|
||||||
|
|
||||||
|
Before loading data from SD, format your SD card as FAT and run the `examples/storage/sd_card` example on it to verify that it's working as expected in ESP-IDF. This helps cut down the possible causes of errors in the more complex AWS IoT examples!
|
||||||
|
|
||||||
|
Run `make menuconfig`, navigate to "Example Configuration" and change "AWS IoT Certificate Source" to "Load from SD card".
|
||||||
|
|
||||||
|
Three new prompts will appear for filenames for the device key, device certificate and root CA certificate path. These paths start with `/sdcard/` as this is where the example mounts the (FAT formatted) SD card.
|
||||||
|
|
||||||
|
Copy the certificate and key files to the SD card, and make sure the file names match the names given in the example configuration (either rename the files, or change the config). For the Root CA certificate file (which is not device-specific), you can find the file in the `main/certs` directory or download it from AWS.
|
||||||
|
|
||||||
|
*Note: By default, esp-idf's FATFS support only allows 8.3 character filenames. However, the AWS IoT examples pre-configure the sdkconfig to enable long filenames. If you're setting up your projects, you will probably want to enable these options as well (under Component Config -> FAT Filesystem Support). You can also consider configure the FAT filesystem for read-only support, if you don't need to write to the SD card.*
|
||||||
|
|
||||||
|
## Find & Set AWS Endpoint Hostname
|
||||||
|
|
||||||
|
Your AWS IoT account has a unique endpoint hostname to connect to. To find it, open the AWS IoT Console and click the "Settings" button on the bottom left side. The endpoint hostname is shown under the "Custom Endpoint" heading on this page.
|
||||||
|
|
||||||
|
Run `make menuconfig` and navigate to `Component Config` -> `Amazon Web Service IoT Config` -> `AWS IoT MQTT Hostname`. Enter the host name here.
|
||||||
|
|
||||||
|
*Note: It may seem odd that you have to configure parts of the AWS settings under Component Config and some under Example Configuration.* The IoT MQTT Hostname and Port are set as part of the component because when using the AWS IoT SDK's Thing Shadow API (in examples or in other projects) the `ShadowInitParametersDefault` structure means the Thing Shadow connection will default to that host & port. You're not forced to use these config values in your own projects, you can set the values in code via the AWS IoT SDK's init parameter structures - `ShadowInitParameters_t` for Thing Shadow API or `IoT_Client_Init_Params` for MQTT API.
|
||||||
|
|
||||||
|
### (Optional) Set Client ID
|
||||||
|
|
||||||
|
Run `make menuconfig`. Under `Example Configuration`, set the `AWS IoT Client ID` to a unique value.
|
||||||
|
|
||||||
|
The Client ID is used in the MQTT protocol used to send messages to/from AWS IoT. AWS IoT requires that each connected device within a single AWS account uses a unique Client ID. Other than this restriction, the Client ID can be any value that you like. The example default should be fine if you're only connecting one ESP32 at a time.
|
||||||
|
|
||||||
|
In a production IoT app this ID would be set dynamically, but for these examples it is compiled in via menuconfig.
|
||||||
|
|
||||||
|
### (Optional) Locally Check The Root Certificate
|
||||||
|
|
||||||
|
The Root CA certificate provides a root-of-trust when the ESP32 connects to AWS IoT. We have supplied the root CA certificate already (in PEM format) in the file `main/certs/aws-root-ca.pem`.
|
||||||
|
|
||||||
|
If you want to locally verify that this Root CA certificate hasn't changed, you can run the following command against your AWS MQTT Host:
|
||||||
|
|
||||||
|
```
|
||||||
|
openssl s_client -showcerts -connect hostname:8883 < /dev/null
|
||||||
|
```
|
||||||
|
|
||||||
|
(Replace hostname with your AWS MQTT endpoint host.) The Root CA certificate is the last certificate in the list of certificates printed. You can copy-paste this in place of the existing `aws-root-ca.pem` file.
|
||||||
|
|
||||||
|
|
||||||
|
# Troubleshooting
|
||||||
|
|
||||||
|
## Tips
|
||||||
|
|
||||||
|
* Raise the ESP debug log level to Debug in order to see messages about the connection to AWS, certificate contents, etc.
|
||||||
|
|
||||||
|
* Enable mbedTLS debugging (under Components -> mbedTLS -> mbedTLS Debug) in order to see even more low-level debug output from the mbedTLS layer.
|
||||||
|
|
||||||
|
* To create a successful AWS IoT connection, the following factors must all be present:
|
||||||
|
- Endpoint hostname is correct for your AWS account.
|
||||||
|
- Certificate & private key are both attached to correct Thing in AWS IoT Console.
|
||||||
|
- Certificate is activated.
|
||||||
|
- Policy is attached to the Certificate in AWS IoT Console.
|
||||||
|
- Policy contains sufficient permissions to authorize AWS IoT connection.
|
||||||
|
|
||||||
|
## TLS connection fails
|
||||||
|
|
||||||
|
If connecting fails entirely (handshake doesn't complete), this usually indicates a problem with certification configuration. The error usually looks like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
aws_iot: failed! mbedtls_ssl_handshake returned -0x7780
|
||||||
|
```
|
||||||
|
|
||||||
|
(0x7780 is the mbedTLS error code when the server sends an alert message and closes the connection.)
|
||||||
|
|
||||||
|
* Check your client private key and certificate file match a Certificate registered and **activated** in AWS IoT console. You can find the Certificate in IoT Console in one of two ways, via the Thing or via Certificates:
|
||||||
|
- To find the Certificate directly, click on "Registry" -> "Security Certificates". Then click on the Certificate itself to view it.
|
||||||
|
- To find the Certificate via the Thing, click on "Registry" -> "Things", then click on the particular Thing you are using. Click "Certificates" in the sidebar to view all Certificates attached to that Thing. Then click on the Certificate itself to view it.
|
||||||
|
|
||||||
|
Verify the Certificate is activated (when viewing the Certificate, it will say "ACTIVE" or "INACTIVE" near the top under the certificate name).
|
||||||
|
|
||||||
|
If the Certificate appears correct and activated, verify that you are connecting to the correct AWS IoT endpoint (see above.)
|
||||||
|
|
||||||
|
## TLS connection closes immediately
|
||||||
|
|
||||||
|
Sometimes connecting is successful (the handshake completes) but as soon as the client sends its `MQTT CONNECT` message the server sends back a TLS alert and closes the connection, without anything else happening.
|
||||||
|
|
||||||
|
The error returned from AWS IoT is usually -28 (`MQTT_REQUEST_TIMEOUT_ERROR`). You may also see mbedtls error `-0x7780` (server alert), although if this error comes during `mbedtls_ssl_handshake` then it's usually a different problem (see above).
|
||||||
|
|
||||||
|
In the subscribe_publish example, the error may look like this in the log:
|
||||||
|
|
||||||
|
```
|
||||||
|
subpub: Error(-28) connecting to (endpoint)...
|
||||||
|
```
|
||||||
|
|
||||||
|
In the thing_shadow example, the error may look like this in the log:
|
||||||
|
|
||||||
|
```
|
||||||
|
shadow: aws_iot_shadow_connect returned error -28, aborting...
|
||||||
|
```
|
||||||
|
|
||||||
|
This error implies the Certificate is recognised, but the Certificate is either missing the correct Thing or the correct Policy attached to it.
|
||||||
|
|
||||||
|
* Check in the AWS IoT console that your certificate is activated and has both a **security policy** and a **Thing** attached to it. You can find this in IoT Console by clicking "Registry" -> "Security Certificates", then click the Certificate. Once viewing the Certificate, you can click the "Policies" and "Things" links in the sidebar.
|
||||||
|
|
9
examples/protocols/aws_iot/subscribe_publish/Makefile
Normal file
9
examples/protocols/aws_iot/subscribe_publish/Makefile
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#
|
||||||
|
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||||
|
# project subdirectory.
|
||||||
|
#
|
||||||
|
|
||||||
|
PROJECT_NAME := aws_iot_subpub
|
||||||
|
|
||||||
|
include $(IDF_PATH)/make/project.mk
|
||||||
|
|
32
examples/protocols/aws_iot/subscribe_publish/README.md
Normal file
32
examples/protocols/aws_iot/subscribe_publish/README.md
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
# Amazon Web Services IoT MQTT Subscribe/Publish Example
|
||||||
|
|
||||||
|
This is an adaptation of the [AWS IoT C SDK](https://github.com/aws/aws-iot-device-sdk-embedded-C) "subscribe_publish" example for ESP-IDF.
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
|
||||||
|
See the README.md in the parent directory for information about configuring the AWS IoT examples.
|
||||||
|
|
||||||
|
# Monitoring MQTT Data from the device
|
||||||
|
|
||||||
|
After flashing the example to your ESP32, it should connect to Amazon and start subscribing/publishing MQTT data.
|
||||||
|
|
||||||
|
The example code publishes MQTT data to the topic `test_topic/esp32`. Amazon provides a web interface to subscribe to MQTT topics for testing:
|
||||||
|
|
||||||
|
* On the AWS IoT console, click "MQTT Client" near the top-right.
|
||||||
|
* Click "Generate Client ID" to generate a random client ID.
|
||||||
|
* Click "Connect"
|
||||||
|
|
||||||
|
One connection succeeds, you can subscribe to the data published by the ESP32:
|
||||||
|
|
||||||
|
* Click "Subscribe to Topic"
|
||||||
|
* Enter "Subscription Topic" `test_topic/esp32`
|
||||||
|
* Click "Subscribe"
|
||||||
|
|
||||||
|
... you should see MQTT data published from the running example.
|
||||||
|
|
||||||
|
To publish data back to the device:
|
||||||
|
|
||||||
|
* Click "Publish to Topic"
|
||||||
|
* Enter "Publish Topic" `test_topic/esp32`
|
||||||
|
* Enter a message in the payload field
|
||||||
|
* Click Publish
|
|
@ -0,0 +1,60 @@
|
||||||
|
menu "Example Configuration"
|
||||||
|
|
||||||
|
config WIFI_SSID
|
||||||
|
string "WiFi SSID"
|
||||||
|
default "myssid"
|
||||||
|
help
|
||||||
|
SSID (network name) for the example to connect to.
|
||||||
|
|
||||||
|
config WIFI_PASSWORD
|
||||||
|
string "WiFi Password"
|
||||||
|
default "myssid"
|
||||||
|
help
|
||||||
|
WiFi password (WPA or WPA2) for the example to use.
|
||||||
|
|
||||||
|
Can be left blank if the network has no security set.
|
||||||
|
|
||||||
|
config AWS_EXAMPLE_CLIENT_ID
|
||||||
|
string "AWS IoT Client ID"
|
||||||
|
default "myesp32"
|
||||||
|
help
|
||||||
|
AWS IoT Client ID for the example. Should be unique for every device.
|
||||||
|
|
||||||
|
choice EXAMPLE_CERT_SOURCE
|
||||||
|
prompt "AWS IoT Certificate Source"
|
||||||
|
default EXAMPLE_EMBEDDED_CERTS
|
||||||
|
help
|
||||||
|
AWS IoT requires loading of a device-specific certificate and private key,
|
||||||
|
and a common Root CA Certificate. These can be compiled into the example
|
||||||
|
app, or they can be loaded via the filesystem from an SD card.
|
||||||
|
|
||||||
|
config EXAMPLE_EMBEDDED_CERTS
|
||||||
|
bool "Embed into app"
|
||||||
|
config EXAMPLE_SDCARD_CERTS
|
||||||
|
bool "Load from SD card"
|
||||||
|
select EXAMPLE_FILESYSTEM_CERTS
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
# Currently this is equivalent to EXAMPLE_SDCARD_CERTS,
|
||||||
|
# however eventually we want to support more filesystem
|
||||||
|
# sources (SPIFFS, etc.) So this hidden config item
|
||||||
|
# is selected whenever the item should load from filesystem.
|
||||||
|
config EXAMPLE_FILESYSTEM_CERTS
|
||||||
|
bool
|
||||||
|
|
||||||
|
config EXAMPLE_CERTIFICATE_PATH
|
||||||
|
string "Device Certificate Path"
|
||||||
|
depends on EXAMPLE_FILESYSTEM_CERTS
|
||||||
|
default "/sdcard/certificate.pem.crt"
|
||||||
|
|
||||||
|
config EXAMPLE_PRIVATE_KEY_PATH
|
||||||
|
string "Device Private Key Path"
|
||||||
|
depends on EXAMPLE_FILESYSTEM_CERTS
|
||||||
|
default "/sdcard/private.pem.key"
|
||||||
|
|
||||||
|
config EXAMPLE_ROOT_CA_PATH
|
||||||
|
string "Root CA Certificate Path"
|
||||||
|
depends on EXAMPLE_FILESYSTEM_CERTS
|
||||||
|
default "/sdcard/aws-root-ca.pem"
|
||||||
|
|
||||||
|
endmenu
|
|
@ -0,0 +1,3 @@
|
||||||
|
Copy certificate files for AWS IoT SDK example here
|
||||||
|
|
||||||
|
See README.md in main example directory for details.
|
|
@ -0,0 +1,28 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB
|
||||||
|
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
|
||||||
|
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
|
||||||
|
U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
|
||||||
|
ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
|
||||||
|
aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL
|
||||||
|
MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
|
||||||
|
ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln
|
||||||
|
biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
|
||||||
|
U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
|
||||||
|
aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1
|
||||||
|
nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex
|
||||||
|
t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz
|
||||||
|
SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG
|
||||||
|
BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+
|
||||||
|
rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/
|
||||||
|
NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
|
||||||
|
BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH
|
||||||
|
BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
|
||||||
|
aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv
|
||||||
|
MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE
|
||||||
|
p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y
|
||||||
|
5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK
|
||||||
|
WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
|
||||||
|
4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
|
||||||
|
hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
|
||||||
|
-----END CERTIFICATE-----
|
|
@ -0,0 +1,22 @@
|
||||||
|
#
|
||||||
|
# Main Makefile. This is basically the same as a component makefile.
|
||||||
|
#
|
||||||
|
|
||||||
|
ifdef CONFIG_EXAMPLE_EMBEDDED_CERTS
|
||||||
|
# Certificate files. certificate.pem.crt & private.pem.key must be downloaded
|
||||||
|
# from AWS, see README for details.
|
||||||
|
COMPONENT_EMBED_TXTFILES := certs/aws-root-ca.pem certs/certificate.pem.crt certs/private.pem.key
|
||||||
|
|
||||||
|
ifndef IDF_CI_BUILD
|
||||||
|
# Print an error if the certificate/key files are missing
|
||||||
|
$(COMPONENT_PATH)/certs/certificate.pem.crt $(COMPONENT_PATH)/certs/private.pem.key:
|
||||||
|
@echo "Missing PEM file $@. This file identifies the ESP32 to AWS for the example, see README for details."
|
||||||
|
exit 1
|
||||||
|
else # IDF_CI_BUILD
|
||||||
|
# this case is for the internal Continuous Integration build which
|
||||||
|
# compiles all examples. Add some dummy certs so the example can
|
||||||
|
# compile (even though it won't work)
|
||||||
|
$(COMPONENT_PATH)/certs/certificate.pem.crt $(COMPONENT_PATH)/certs/private.pem.key:
|
||||||
|
echo "Dummy certificate data for continuous integration" > $@
|
||||||
|
endif
|
||||||
|
endif
|
|
@ -0,0 +1,326 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Additions Copyright 2016 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
* A copy of the License is located at
|
||||||
|
*
|
||||||
|
* http://aws.amazon.com/apache2.0
|
||||||
|
*
|
||||||
|
* or in the "license" file accompanying this file. This file is distributed
|
||||||
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||||
|
* express or implied. See the License for the specific language governing
|
||||||
|
* permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @file subscribe_publish_sample.c
|
||||||
|
* @brief simple MQTT publish and subscribe on the same topic
|
||||||
|
*
|
||||||
|
* This example takes the parameters from the build configuration and establishes a connection to the AWS IoT MQTT Platform.
|
||||||
|
* It subscribes and publishes to the same topic - "test_topic/esp32"
|
||||||
|
*
|
||||||
|
* Some setup is required. See example README for details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "freertos/event_groups.h"
|
||||||
|
#include "esp_system.h"
|
||||||
|
#include "esp_wifi.h"
|
||||||
|
#include "esp_event_loop.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_vfs_fat.h"
|
||||||
|
#include "driver/sdmmc_host.h"
|
||||||
|
|
||||||
|
#include "aws_iot_config.h"
|
||||||
|
#include "aws_iot_log.h"
|
||||||
|
#include "aws_iot_version.h"
|
||||||
|
#include "aws_iot_mqtt_client_interface.h"
|
||||||
|
|
||||||
|
static const char *TAG = "subpub";
|
||||||
|
|
||||||
|
/* The examples use simple WiFi 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_WIFI_SSID "mywifissid"
|
||||||
|
*/
|
||||||
|
#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID
|
||||||
|
#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD
|
||||||
|
|
||||||
|
/* FreeRTOS event group to signal when we are connected & ready to make a request */
|
||||||
|
static EventGroupHandle_t wifi_event_group;
|
||||||
|
|
||||||
|
/* The event group allows multiple bits for each event,
|
||||||
|
but we only care about one event - are we connected
|
||||||
|
to the AP with an IP? */
|
||||||
|
const int CONNECTED_BIT = BIT0;
|
||||||
|
|
||||||
|
|
||||||
|
/* CA Root certificate, device ("Thing") certificate and device
|
||||||
|
* ("Thing") key.
|
||||||
|
|
||||||
|
Example can be configured one of two ways:
|
||||||
|
|
||||||
|
"Embedded Certs" are loaded from files in "certs/" and embedded into the app binary.
|
||||||
|
|
||||||
|
"Filesystem Certs" are loaded from the filesystem (SD card, etc.)
|
||||||
|
|
||||||
|
See example README for more details.
|
||||||
|
*/
|
||||||
|
#if defined(CONFIG_EXAMPLE_EMBEDDED_CERTS)
|
||||||
|
|
||||||
|
extern const uint8_t aws_root_ca_pem_start[] asm("_binary_aws_root_ca_pem_start");
|
||||||
|
extern const uint8_t aws_root_ca_pem_end[] asm("_binary_aws_root_ca_pem_end");
|
||||||
|
extern const uint8_t certificate_pem_crt_start[] asm("_binary_certificate_pem_crt_start");
|
||||||
|
extern const uint8_t certificate_pem_crt_end[] asm("_binary_certificate_pem_crt_end");
|
||||||
|
extern const uint8_t private_pem_key_start[] asm("_binary_private_pem_key_start");
|
||||||
|
extern const uint8_t private_pem_key_end[] asm("_binary_private_pem_key_end");
|
||||||
|
|
||||||
|
#elif defined(CONFIG_EXAMPLE_FILESYSTEM_CERTS)
|
||||||
|
|
||||||
|
static const char * DEVICE_CERTIFICATE_PATH = CONFIG_EXAMPLE_CERTIFICATE_PATH;
|
||||||
|
static const char * DEVICE_PRIVATE_KEY_PATH = CONFIG_EXAMPLE_PRIVATE_KEY_PATH;
|
||||||
|
static const char * ROOT_CA_PATH = CONFIG_EXAMPLE_ROOT_CA_PATH;
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "Invalid method for loading certs"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Default MQTT HOST URL is pulled from the aws_iot_config.h
|
||||||
|
*/
|
||||||
|
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 esp_err_t event_handler(void *ctx, system_event_t *event)
|
||||||
|
{
|
||||||
|
switch(event->event_id) {
|
||||||
|
case SYSTEM_EVENT_STA_START:
|
||||||
|
esp_wifi_connect();
|
||||||
|
break;
|
||||||
|
case SYSTEM_EVENT_STA_GOT_IP:
|
||||||
|
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
|
||||||
|
break;
|
||||||
|
case SYSTEM_EVENT_STA_DISCONNECTED:
|
||||||
|
/* This is a workaround as ESP32 WiFi libs don't currently
|
||||||
|
auto-reassociate. */
|
||||||
|
esp_wifi_connect();
|
||||||
|
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iot_subscribe_callback_handler(AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen,
|
||||||
|
IoT_Publish_Message_Params *params, void *pData) {
|
||||||
|
ESP_LOGI(TAG, "Subscribe callback");
|
||||||
|
ESP_LOGI(TAG, "%.*s\t%.*s", topicNameLen, topicName, (int) params->payloadLen, (char *)params->payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
void disconnectCallbackHandler(AWS_IoT_Client *pClient, void *data) {
|
||||||
|
ESP_LOGW(TAG, "MQTT Disconnect");
|
||||||
|
IoT_Error_t rc = FAILURE;
|
||||||
|
|
||||||
|
if(NULL == pClient) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(aws_iot_is_autoreconnect_enabled(pClient)) {
|
||||||
|
ESP_LOGI(TAG, "Auto Reconnect is enabled, Reconnecting attempt will start now");
|
||||||
|
} else {
|
||||||
|
ESP_LOGW(TAG, "Auto Reconnect not enabled. Starting manual reconnect...");
|
||||||
|
rc = aws_iot_mqtt_attempt_reconnect(pClient);
|
||||||
|
if(NETWORK_RECONNECTED == rc) {
|
||||||
|
ESP_LOGW(TAG, "Manual Reconnect Successful");
|
||||||
|
} else {
|
||||||
|
ESP_LOGW(TAG, "Manual Reconnect Failed - %d", rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void aws_iot_task(void *param) {
|
||||||
|
char cPayload[100];
|
||||||
|
|
||||||
|
int32_t i = 0;
|
||||||
|
|
||||||
|
IoT_Error_t rc = FAILURE;
|
||||||
|
|
||||||
|
AWS_IoT_Client client;
|
||||||
|
IoT_Client_Init_Params mqttInitParams = iotClientInitParamsDefault;
|
||||||
|
IoT_Client_Connect_Params connectParams = iotClientConnectParamsDefault;
|
||||||
|
|
||||||
|
IoT_Publish_Message_Params paramsQOS0;
|
||||||
|
IoT_Publish_Message_Params paramsQOS1;
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "AWS IoT SDK Version %d.%d.%d-%s", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_TAG);
|
||||||
|
|
||||||
|
mqttInitParams.enableAutoReconnect = false; // We enable this later below
|
||||||
|
mqttInitParams.pHostURL = HostAddress;
|
||||||
|
mqttInitParams.port = port;
|
||||||
|
|
||||||
|
#if defined(CONFIG_EXAMPLE_EMBEDDED_CERTS)
|
||||||
|
mqttInitParams.pRootCALocation = (const char *)aws_root_ca_pem_start;
|
||||||
|
mqttInitParams.pDeviceCertLocation = (const char *)certificate_pem_crt_start;
|
||||||
|
mqttInitParams.pDevicePrivateKeyLocation = (const char *)private_pem_key_start;
|
||||||
|
|
||||||
|
#elif defined(CONFIG_EXAMPLE_FILESYSTEM_CERTS)
|
||||||
|
mqttInitParams.pRootCALocation = ROOT_CA_PATH;
|
||||||
|
mqttInitParams.pDeviceCertLocation = DEVICE_CERTIFICATE_PATH;
|
||||||
|
mqttInitParams.pDevicePrivateKeyLocation = DEVICE_PRIVATE_KEY_PATH;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mqttInitParams.mqttCommandTimeout_ms = 20000;
|
||||||
|
mqttInitParams.tlsHandshakeTimeout_ms = 5000;
|
||||||
|
mqttInitParams.isSSLHostnameVerify = true;
|
||||||
|
mqttInitParams.disconnectHandler = disconnectCallbackHandler;
|
||||||
|
mqttInitParams.disconnectHandlerData = NULL;
|
||||||
|
|
||||||
|
#ifdef CONFIG_EXAMPLE_SDCARD_CERTS
|
||||||
|
ESP_LOGI(TAG, "Mounting SD card...");
|
||||||
|
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
|
||||||
|
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
|
||||||
|
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
|
||||||
|
.format_if_mount_failed = false,
|
||||||
|
.max_files = 3,
|
||||||
|
};
|
||||||
|
sdmmc_card_t* card;
|
||||||
|
esp_err_t ret = esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, &card);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "Failed to mount SD card VFAT filesystem.");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
rc = aws_iot_mqtt_init(&client, &mqttInitParams);
|
||||||
|
if(SUCCESS != rc) {
|
||||||
|
ESP_LOGE(TAG, "aws_iot_mqtt_init returned error : %d ", rc);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait for WiFI to show as connected */
|
||||||
|
xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
|
||||||
|
false, true, portMAX_DELAY);
|
||||||
|
|
||||||
|
connectParams.keepAliveIntervalInSec = 10;
|
||||||
|
connectParams.isCleanSession = true;
|
||||||
|
connectParams.MQTTVersion = MQTT_3_1_1;
|
||||||
|
/* Client ID is set in the menuconfig of the example */
|
||||||
|
connectParams.pClientID = CONFIG_AWS_EXAMPLE_CLIENT_ID;
|
||||||
|
connectParams.clientIDLen = (uint16_t) strlen(CONFIG_AWS_EXAMPLE_CLIENT_ID);
|
||||||
|
connectParams.isWillMsgPresent = false;
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Connecting to AWS...");
|
||||||
|
do {
|
||||||
|
rc = aws_iot_mqtt_connect(&client, &connectParams);
|
||||||
|
if(SUCCESS != rc) {
|
||||||
|
ESP_LOGE(TAG, "Error(%d) connecting to %s:%d", rc, mqttInitParams.pHostURL, mqttInitParams.port);
|
||||||
|
vTaskDelay(1000 / portTICK_RATE_MS);
|
||||||
|
}
|
||||||
|
} while(SUCCESS != rc);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable Auto Reconnect functionality. Minimum and Maximum time of Exponential backoff are set in aws_iot_config.h
|
||||||
|
* #AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL
|
||||||
|
* #AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL
|
||||||
|
*/
|
||||||
|
rc = aws_iot_mqtt_autoreconnect_set_status(&client, true);
|
||||||
|
if(SUCCESS != rc) {
|
||||||
|
ESP_LOGE(TAG, "Unable to set Auto Reconnect to true - %d", rc);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *TOPIC = "test_topic/esp32";
|
||||||
|
const int TOPIC_LEN = strlen(TOPIC);
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Subscribing...");
|
||||||
|
rc = aws_iot_mqtt_subscribe(&client, TOPIC, TOPIC_LEN, QOS0, iot_subscribe_callback_handler, NULL);
|
||||||
|
if(SUCCESS != rc) {
|
||||||
|
ESP_LOGE(TAG, "Error subscribing : %d ", rc);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(cPayload, "%s : %d ", "hello from SDK", i);
|
||||||
|
|
||||||
|
paramsQOS0.qos = QOS0;
|
||||||
|
paramsQOS0.payload = (void *) cPayload;
|
||||||
|
paramsQOS0.isRetained = 0;
|
||||||
|
|
||||||
|
paramsQOS1.qos = QOS1;
|
||||||
|
paramsQOS1.payload = (void *) cPayload;
|
||||||
|
paramsQOS1.isRetained = 0;
|
||||||
|
|
||||||
|
while((NETWORK_ATTEMPTING_RECONNECT == rc || NETWORK_RECONNECTED == rc || SUCCESS == rc)) {
|
||||||
|
|
||||||
|
//Max time the yield function will wait for read messages
|
||||||
|
rc = aws_iot_mqtt_yield(&client, 100);
|
||||||
|
if(NETWORK_ATTEMPTING_RECONNECT == rc) {
|
||||||
|
// If the client is attempting to reconnect we will skip the rest of the loop.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "-->sleep");
|
||||||
|
vTaskDelay(1000 / portTICK_RATE_MS);
|
||||||
|
sprintf(cPayload, "%s : %d ", "hello from ESP32 (QOS0)", i++);
|
||||||
|
paramsQOS0.payloadLen = strlen(cPayload);
|
||||||
|
rc = aws_iot_mqtt_publish(&client, TOPIC, TOPIC_LEN, ¶msQOS0);
|
||||||
|
|
||||||
|
sprintf(cPayload, "%s : %d ", "hello from ESP32 (QOS1)", i++);
|
||||||
|
paramsQOS1.payloadLen = strlen(cPayload);
|
||||||
|
rc = aws_iot_mqtt_publish(&client, TOPIC, TOPIC_LEN, ¶msQOS1);
|
||||||
|
if (rc == MQTT_REQUEST_TIMEOUT_ERROR) {
|
||||||
|
ESP_LOGW(TAG, "QOS1 publish ack not received.");
|
||||||
|
rc = SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGE(TAG, "An error occurred in the main loop.");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void initialise_wifi(void)
|
||||||
|
{
|
||||||
|
tcpip_adapter_init();
|
||||||
|
wifi_event_group = xEventGroupCreate();
|
||||||
|
ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );
|
||||||
|
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||||
|
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
|
||||||
|
ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
|
||||||
|
wifi_config_t wifi_config = {
|
||||||
|
.sta = {
|
||||||
|
.ssid = EXAMPLE_WIFI_SSID,
|
||||||
|
.password = EXAMPLE_WIFI_PASS,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
|
||||||
|
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
|
||||||
|
ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
|
||||||
|
ESP_ERROR_CHECK( esp_wifi_start() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void app_main()
|
||||||
|
{
|
||||||
|
initialise_wifi();
|
||||||
|
#ifdef CONFIG_MBEDTLS_DEBUG
|
||||||
|
const size_t stack_size = 36*1024;
|
||||||
|
#else
|
||||||
|
const size_t stack_size = 36*1024;
|
||||||
|
#endif
|
||||||
|
xTaskCreatePinnedToCore(&aws_iot_task, "aws_iot_task", stack_size, NULL, 5, NULL, 1);
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Enable AWS IoT SDK support
|
||||||
|
CONFIG_AWS_IOT_SDK=y
|
||||||
|
|
||||||
|
# Enable FATFS read only with long filename support
|
||||||
|
# for loading Cert/CA/etc from filesystem
|
||||||
|
# (if enabled in config)
|
||||||
|
CONFIG_FATFS_READONLY=y
|
||||||
|
CONFIG_FATFS_CODEPAGE_437=y
|
||||||
|
CONFIG_FATFS_LFN_HEAP=y
|
9
examples/protocols/aws_iot/thing_shadow/Makefile
Normal file
9
examples/protocols/aws_iot/thing_shadow/Makefile
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#
|
||||||
|
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||||
|
# project subdirectory.
|
||||||
|
#
|
||||||
|
|
||||||
|
PROJECT_NAME := aws_iot_thing_shadow
|
||||||
|
|
||||||
|
include $(IDF_PATH)/make/project.mk
|
||||||
|
|
34
examples/protocols/aws_iot/thing_shadow/README.md
Normal file
34
examples/protocols/aws_iot/thing_shadow/README.md
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
# Amazon Web Services IoT Thing Shadow Example
|
||||||
|
|
||||||
|
This is an adaptation of the [AWS IoT C SDK](https://github.com/aws/aws-iot-device-sdk-embedded-C) "shadow_sample" example for ESP-IDF.
|
||||||
|
|
||||||
|
# Provisioning/Configuration
|
||||||
|
|
||||||
|
See the README.md in the parent directory for information about configuring the AWS IoT examples.
|
||||||
|
|
||||||
|
After following those steps, there is one additional step for this exmaple:
|
||||||
|
|
||||||
|
## Set Thing Name
|
||||||
|
|
||||||
|
For this example, you will need to set a Thing Name under `make menuconfig` -> `Example Configuration` -> `AWS IoT Thing Name`.
|
||||||
|
|
||||||
|
The Thing Name should match a Thing that you created while following the Getting Started guide (to check the Things you have registered, go t othe AWS IoT console web interface, click Registry and then click Things).
|
||||||
|
|
||||||
|
# Monitoring Thing Status
|
||||||
|
|
||||||
|
After flashing the example to your ESP32, it should connect to Amazon and start updating the example Thing's shadow.
|
||||||
|
|
||||||
|
In the ESP32's serial output, you should see the message "Update accepted" logged every couple of seconds.
|
||||||
|
|
||||||
|
You can monitor the Thing status from the AWS IoT console web interface:
|
||||||
|
|
||||||
|
* On the left-hand toolbar, click Registry and then click Things.
|
||||||
|
* Click on the "Thing" you set up for the example.
|
||||||
|
* Click on the "Shadow" sidebar link. You should see the Thing Shadow updating regularly.
|
||||||
|
* Click on the "Activity" sidebar link to see all Thing Shadow updates in a list. You can examine each update individually.
|
||||||
|
|
||||||
|
# Troubleshooting
|
||||||
|
|
||||||
|
If you're having problems with the AWS IoT connection itself, check the Troubleshooting section of the README in the parent directory.
|
||||||
|
|
||||||
|
* If your Thing is connecting and appears to be successfully updating, but you don't see any updates in the AWS IoT console, then check that the Thing Name in the Example Configuration under menuconfig matches exactly the thing name in AWS IoT console (including case).
|
|
@ -0,0 +1,66 @@
|
||||||
|
menu "Example Configuration"
|
||||||
|
|
||||||
|
config WIFI_SSID
|
||||||
|
string "WiFi SSID"
|
||||||
|
default "myssid"
|
||||||
|
help
|
||||||
|
SSID (network name) for the example to connect to.
|
||||||
|
|
||||||
|
config WIFI_PASSWORD
|
||||||
|
string "WiFi Password"
|
||||||
|
default "myssid"
|
||||||
|
help
|
||||||
|
WiFi password (WPA or WPA2) for the example to use.
|
||||||
|
|
||||||
|
Can be left blank if the network has no security set.
|
||||||
|
|
||||||
|
config AWS_EXAMPLE_CLIENT_ID
|
||||||
|
string "AWS IoT Client ID"
|
||||||
|
default "myesp32"
|
||||||
|
help
|
||||||
|
AWS IoT Client ID for the example. Should be unique for every device.
|
||||||
|
|
||||||
|
config AWS_EXAMPLE_THING_NAME
|
||||||
|
string "AWS IoT Thing Name"
|
||||||
|
default "myesp32"
|
||||||
|
help
|
||||||
|
AWS IoT Thing Name for the example. Should be unique for every device.
|
||||||
|
|
||||||
|
choice EXAMPLE_CERT_SOURCE
|
||||||
|
prompt "AWS IoT Certificate Source"
|
||||||
|
default EXAMPLE_EMBEDDED_CERTS
|
||||||
|
help
|
||||||
|
AWS IoT requires loading of a device-specific certificate and private key,
|
||||||
|
and a common Root CA Certificate. These can be compiled into the example
|
||||||
|
app, or they can be loaded via the filesystem from an SD card.
|
||||||
|
|
||||||
|
config EXAMPLE_EMBEDDED_CERTS
|
||||||
|
bool "Embed into app"
|
||||||
|
config EXAMPLE_SDCARD_CERTS
|
||||||
|
bool "Load from SD card"
|
||||||
|
select EXAMPLE_FILESYSTEM_CERTS
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
# Currently this is equivalent to EXAMPLE_SDCARD_CERTS,
|
||||||
|
# however eventually we want to support more filesystem
|
||||||
|
# sources (SPIFFS, etc.) So this hidden config item
|
||||||
|
# is selected whenever the item should load from filesystem.
|
||||||
|
config EXAMPLE_FILESYSTEM_CERTS
|
||||||
|
bool
|
||||||
|
|
||||||
|
config EXAMPLE_CERTIFICATE_PATH
|
||||||
|
string "Device Certificate Path"
|
||||||
|
depends on EXAMPLE_FILESYSTEM_CERTS
|
||||||
|
default "/sdcard/certificate.pem.crt"
|
||||||
|
|
||||||
|
config EXAMPLE_PRIVATE_KEY_PATH
|
||||||
|
string "Device Private Key Path"
|
||||||
|
depends on EXAMPLE_FILESYSTEM_CERTS
|
||||||
|
default "/sdcard/private.pem.key"
|
||||||
|
|
||||||
|
config EXAMPLE_ROOT_CA_PATH
|
||||||
|
string "Root CA Certificate Path"
|
||||||
|
depends on EXAMPLE_FILESYSTEM_CERTS
|
||||||
|
default "/sdcard/aws-root-ca.pem"
|
||||||
|
|
||||||
|
endmenu
|
|
@ -0,0 +1,3 @@
|
||||||
|
Copy certificate files for AWS IoT SDK example here
|
||||||
|
|
||||||
|
See README.md in main example directory for details.
|
|
@ -0,0 +1,28 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB
|
||||||
|
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
|
||||||
|
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
|
||||||
|
U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
|
||||||
|
ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
|
||||||
|
aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL
|
||||||
|
MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
|
||||||
|
ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln
|
||||||
|
biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
|
||||||
|
U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
|
||||||
|
aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1
|
||||||
|
nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex
|
||||||
|
t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz
|
||||||
|
SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG
|
||||||
|
BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+
|
||||||
|
rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/
|
||||||
|
NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
|
||||||
|
BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH
|
||||||
|
BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
|
||||||
|
aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv
|
||||||
|
MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE
|
||||||
|
p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y
|
||||||
|
5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK
|
||||||
|
WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
|
||||||
|
4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
|
||||||
|
hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
|
||||||
|
-----END CERTIFICATE-----
|
22
examples/protocols/aws_iot/thing_shadow/main/component.mk
Normal file
22
examples/protocols/aws_iot/thing_shadow/main/component.mk
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#
|
||||||
|
# Main Makefile. This is basically the same as a component makefile.
|
||||||
|
#
|
||||||
|
|
||||||
|
ifdef CONFIG_EXAMPLE_EMBEDDED_CERTS
|
||||||
|
# Certificate files. certificate.pem.crt & private.pem.key must be downloaded
|
||||||
|
# from AWS, see README for details.
|
||||||
|
COMPONENT_EMBED_TXTFILES := certs/aws-root-ca.pem certs/certificate.pem.crt certs/private.pem.key
|
||||||
|
|
||||||
|
ifndef IDF_CI_BUILD
|
||||||
|
# Print an error if the certificate/key files are missing
|
||||||
|
$(COMPONENT_PATH)/certs/certificate.pem.crt $(COMPONENT_PATH)/certs/private.pem.key:
|
||||||
|
@echo "Missing PEM file $@. This file identifies the ESP32 to AWS for the example, see README for details."
|
||||||
|
exit 1
|
||||||
|
else # IDF_CI_BUILD
|
||||||
|
# this case is for the internal Continuous Integration build which
|
||||||
|
# compiles all examples. Add some dummy certs so the example can
|
||||||
|
# compile (even though it won't work)
|
||||||
|
$(COMPONENT_PATH)/certs/certificate.pem.crt $(COMPONENT_PATH)/certs/private.pem.key:
|
||||||
|
echo "Dummy certificate data for continuous integration" > $@
|
||||||
|
endif
|
||||||
|
endif
|
|
@ -0,0 +1,368 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* Additions Copyright 2016 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
* A copy of the License is located at
|
||||||
|
*
|
||||||
|
* http://aws.amazon.com/apache2.0
|
||||||
|
*
|
||||||
|
* or in the "license" file accompanying this file. This file is distributed
|
||||||
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||||
|
* express or implied. See the License for the specific language governing
|
||||||
|
* permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @file thing_shadow_sample.c
|
||||||
|
* @brief A simple connected window example demonstrating the use of Thing Shadow
|
||||||
|
*
|
||||||
|
* See example README for more details.
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "freertos/event_groups.h"
|
||||||
|
#include "esp_system.h"
|
||||||
|
#include "esp_wifi.h"
|
||||||
|
#include "esp_event_loop.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_vfs_fat.h"
|
||||||
|
#include "driver/sdmmc_host.h"
|
||||||
|
|
||||||
|
#include "aws_iot_config.h"
|
||||||
|
#include "aws_iot_log.h"
|
||||||
|
#include "aws_iot_version.h"
|
||||||
|
#include "aws_iot_mqtt_client_interface.h"
|
||||||
|
#include "aws_iot_shadow_interface.h"
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* The goal of this sample application is to demonstrate the capabilities of shadow.
|
||||||
|
* This device(say Connected Window) will open the window of a room based on temperature
|
||||||
|
* It can report to the Shadow the following parameters:
|
||||||
|
* 1. temperature of the room (double)
|
||||||
|
* 2. status of the window (open or close)
|
||||||
|
* It can act on commands from the cloud. In this case it will open or close the window based on the json object "windowOpen" data[open/close]
|
||||||
|
*
|
||||||
|
* The two variables from a device's perspective are double temperature and bool windowOpen
|
||||||
|
* The device needs to act on only on windowOpen variable, so we will create a primitiveJson_t object with callback
|
||||||
|
The Json Document in the cloud will be
|
||||||
|
{
|
||||||
|
"reported": {
|
||||||
|
"temperature": 0,
|
||||||
|
"windowOpen": false
|
||||||
|
},
|
||||||
|
"desired": {
|
||||||
|
"windowOpen": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const char *TAG = "shadow";
|
||||||
|
|
||||||
|
#define ROOMTEMPERATURE_UPPERLIMIT 32.0f
|
||||||
|
#define ROOMTEMPERATURE_LOWERLIMIT 25.0f
|
||||||
|
#define STARTING_ROOMTEMPERATURE ROOMTEMPERATURE_LOWERLIMIT
|
||||||
|
|
||||||
|
#define MAX_LENGTH_OF_UPDATE_JSON_BUFFER 200
|
||||||
|
|
||||||
|
/* The examples use simple WiFi 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_WIFI_SSID "mywifissid"
|
||||||
|
*/
|
||||||
|
#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID
|
||||||
|
#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD
|
||||||
|
|
||||||
|
|
||||||
|
/* FreeRTOS event group to signal when we are connected & ready to make a request */
|
||||||
|
static EventGroupHandle_t wifi_event_group;
|
||||||
|
|
||||||
|
/* The event group allows multiple bits for each event,
|
||||||
|
but we only care about one event - are we connected
|
||||||
|
to the AP with an IP? */
|
||||||
|
const int CONNECTED_BIT = BIT0;
|
||||||
|
|
||||||
|
|
||||||
|
/* CA Root certificate, device ("Thing") certificate and device
|
||||||
|
* ("Thing") key.
|
||||||
|
|
||||||
|
Example can be configured one of two ways:
|
||||||
|
|
||||||
|
"Embedded Certs" are loaded from files in "certs/" and embedded into the app binary.
|
||||||
|
|
||||||
|
"Filesystem Certs" are loaded from the filesystem (SD card, etc.)
|
||||||
|
|
||||||
|
See example README for more details.
|
||||||
|
*/
|
||||||
|
#if defined(CONFIG_EXAMPLE_EMBEDDED_CERTS)
|
||||||
|
|
||||||
|
extern const uint8_t aws_root_ca_pem_start[] asm("_binary_aws_root_ca_pem_start");
|
||||||
|
extern const uint8_t aws_root_ca_pem_end[] asm("_binary_aws_root_ca_pem_end");
|
||||||
|
extern const uint8_t certificate_pem_crt_start[] asm("_binary_certificate_pem_crt_start");
|
||||||
|
extern const uint8_t certificate_pem_crt_end[] asm("_binary_certificate_pem_crt_end");
|
||||||
|
extern const uint8_t private_pem_key_start[] asm("_binary_private_pem_key_start");
|
||||||
|
extern const uint8_t private_pem_key_end[] asm("_binary_private_pem_key_end");
|
||||||
|
|
||||||
|
#elif defined(CONFIG_EXAMPLE_FILESYSTEM_CERTS)
|
||||||
|
|
||||||
|
static const char * DEVICE_CERTIFICATE_PATH = CONFIG_EXAMPLE_CERTIFICATE_PATH;
|
||||||
|
static const char * DEVICE_PRIVATE_KEY_PATH = CONFIG_EXAMPLE_PRIVATE_KEY_PATH;
|
||||||
|
static const char * ROOT_CA_PATH = CONFIG_EXAMPLE_ROOT_CA_PATH;
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "Invalid method for loading certs"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Default MQTT HOST URL is pulled from the aws_iot_config.h which
|
||||||
|
* uses menuconfig to find a default.
|
||||||
|
*/
|
||||||
|
char HostAddress[255] = AWS_IOT_MQTT_HOST;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Default MQTT port is pulled from the aws_iot_config.h which
|
||||||
|
* uses menuconfig to find a default.
|
||||||
|
*/
|
||||||
|
uint32_t port = AWS_IOT_MQTT_PORT;
|
||||||
|
|
||||||
|
static esp_err_t event_handler(void *ctx, system_event_t *event)
|
||||||
|
{
|
||||||
|
switch(event->event_id) {
|
||||||
|
case SYSTEM_EVENT_STA_START:
|
||||||
|
esp_wifi_connect();
|
||||||
|
break;
|
||||||
|
case SYSTEM_EVENT_STA_GOT_IP:
|
||||||
|
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
|
||||||
|
break;
|
||||||
|
case SYSTEM_EVENT_STA_DISCONNECTED:
|
||||||
|
/* This is a workaround as ESP32 WiFi libs don't currently
|
||||||
|
auto-reassociate. */
|
||||||
|
esp_wifi_connect();
|
||||||
|
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void simulateRoomTemperature(float *pRoomTemperature) {
|
||||||
|
static float deltaChange;
|
||||||
|
|
||||||
|
if(*pRoomTemperature >= ROOMTEMPERATURE_UPPERLIMIT) {
|
||||||
|
deltaChange = -0.5f;
|
||||||
|
} else if(*pRoomTemperature <= ROOMTEMPERATURE_LOWERLIMIT) {
|
||||||
|
deltaChange = 0.5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
*pRoomTemperature += deltaChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool shadowUpdateInProgress;
|
||||||
|
|
||||||
|
void ShadowUpdateStatusCallback(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);
|
||||||
|
|
||||||
|
shadowUpdateInProgress = false;
|
||||||
|
|
||||||
|
if(SHADOW_ACK_TIMEOUT == status) {
|
||||||
|
ESP_LOGE(TAG, "Update timed out");
|
||||||
|
} else if(SHADOW_ACK_REJECTED == status) {
|
||||||
|
ESP_LOGE(TAG, "Update rejected");
|
||||||
|
} else if(SHADOW_ACK_ACCEPTED == status) {
|
||||||
|
ESP_LOGI(TAG, "Update accepted");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void windowActuate_Callback(const char *pJsonString, uint32_t JsonStringDataLen, jsonStruct_t *pContext) {
|
||||||
|
IOT_UNUSED(pJsonString);
|
||||||
|
IOT_UNUSED(JsonStringDataLen);
|
||||||
|
|
||||||
|
if(pContext != NULL) {
|
||||||
|
ESP_LOGI(TAG, "Delta - Window state changed to %d", *(bool *) (pContext->pData));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void aws_iot_task(void *param) {
|
||||||
|
IoT_Error_t rc = FAILURE;
|
||||||
|
|
||||||
|
char JsonDocumentBuffer[MAX_LENGTH_OF_UPDATE_JSON_BUFFER];
|
||||||
|
size_t sizeOfJsonDocumentBuffer = sizeof(JsonDocumentBuffer) / sizeof(JsonDocumentBuffer[0]);
|
||||||
|
float temperature = 0.0;
|
||||||
|
|
||||||
|
bool windowOpen = false;
|
||||||
|
jsonStruct_t windowActuator;
|
||||||
|
windowActuator.cb = windowActuate_Callback;
|
||||||
|
windowActuator.pData = &windowOpen;
|
||||||
|
windowActuator.pKey = "windowOpen";
|
||||||
|
windowActuator.type = SHADOW_JSON_BOOL;
|
||||||
|
|
||||||
|
jsonStruct_t temperatureHandler;
|
||||||
|
temperatureHandler.cb = NULL;
|
||||||
|
temperatureHandler.pKey = "temperature";
|
||||||
|
temperatureHandler.pData = &temperature;
|
||||||
|
temperatureHandler.type = SHADOW_JSON_FLOAT;
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "AWS IoT SDK Version %d.%d.%d-%s", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_TAG);
|
||||||
|
|
||||||
|
// initialize the mqtt client
|
||||||
|
AWS_IoT_Client mqttClient;
|
||||||
|
|
||||||
|
ShadowInitParameters_t sp = ShadowInitParametersDefault;
|
||||||
|
sp.pHost = AWS_IOT_MQTT_HOST;
|
||||||
|
sp.port = AWS_IOT_MQTT_PORT;
|
||||||
|
|
||||||
|
#if defined(CONFIG_EXAMPLE_EMBEDDED_CERTS)
|
||||||
|
sp.pClientCRT = (const char *)certificate_pem_crt_start;
|
||||||
|
sp.pClientKey = (const char *)private_pem_key_start;
|
||||||
|
sp.pRootCA = (const char *)aws_root_ca_pem_start;
|
||||||
|
#elif defined(CONFIG_EXAMPLE_FILESYSTEM_CERTS)
|
||||||
|
sp.pClientCRT = DEVICE_CERTIFICATE_PATH;
|
||||||
|
sp.pClientKey = DEVICE_PRIVATE_KEY_PATH;
|
||||||
|
sp.pRootCA = ROOT_CA_PATH;
|
||||||
|
#endif
|
||||||
|
sp.enableAutoReconnect = false;
|
||||||
|
sp.disconnectHandler = NULL;
|
||||||
|
|
||||||
|
#ifdef CONFIG_EXAMPLE_SDCARD_CERTS
|
||||||
|
ESP_LOGI(TAG, "Mounting SD card...");
|
||||||
|
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
|
||||||
|
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
|
||||||
|
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
|
||||||
|
.format_if_mount_failed = false,
|
||||||
|
.max_files = 3,
|
||||||
|
};
|
||||||
|
sdmmc_card_t* card;
|
||||||
|
esp_err_t ret = esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, &card);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "Failed to mount SD card VFAT filesystem.");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Wait for WiFI to show as connected */
|
||||||
|
xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
|
||||||
|
false, true, portMAX_DELAY);
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Shadow Init");
|
||||||
|
rc = aws_iot_shadow_init(&mqttClient, &sp);
|
||||||
|
if(SUCCESS != rc) {
|
||||||
|
ESP_LOGE(TAG, "aws_iot_shadow_init returned error %d, aborting...", rc);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
ShadowConnectParameters_t scp = ShadowConnectParametersDefault;
|
||||||
|
scp.pMyThingName = CONFIG_AWS_EXAMPLE_THING_NAME;
|
||||||
|
scp.pMqttClientId = CONFIG_AWS_EXAMPLE_CLIENT_ID;
|
||||||
|
scp.mqttClientIdLen = (uint16_t) strlen(CONFIG_AWS_EXAMPLE_CLIENT_ID);
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Shadow Connect");
|
||||||
|
rc = aws_iot_shadow_connect(&mqttClient, &scp);
|
||||||
|
if(SUCCESS != rc) {
|
||||||
|
ESP_LOGE(TAG, "aws_iot_shadow_connect returned error %d, aborting...", rc);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable Auto Reconnect functionality. Minimum and Maximum time of Exponential backoff are set in aws_iot_config.h
|
||||||
|
* #AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL
|
||||||
|
* #AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL
|
||||||
|
*/
|
||||||
|
rc = aws_iot_shadow_set_autoreconnect_status(&mqttClient, true);
|
||||||
|
if(SUCCESS != rc) {
|
||||||
|
ESP_LOGE(TAG, "Unable to set Auto Reconnect to true - %d, aborting...", rc);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = aws_iot_shadow_register_delta(&mqttClient, &windowActuator);
|
||||||
|
|
||||||
|
if(SUCCESS != rc) {
|
||||||
|
ESP_LOGE(TAG, "Shadow Register Delta Error");
|
||||||
|
}
|
||||||
|
temperature = STARTING_ROOMTEMPERATURE;
|
||||||
|
|
||||||
|
// loop and publish a change in temperature
|
||||||
|
while(NETWORK_ATTEMPTING_RECONNECT == rc || NETWORK_RECONNECTED == rc || SUCCESS == rc) {
|
||||||
|
rc = aws_iot_shadow_yield(&mqttClient, 200);
|
||||||
|
if(NETWORK_ATTEMPTING_RECONNECT == rc || shadowUpdateInProgress) {
|
||||||
|
rc = aws_iot_shadow_yield(&mqttClient, 1000);
|
||||||
|
// If the client is attempting to reconnect, or already waiting on a shadow update,
|
||||||
|
// we will skip the rest of the loop.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ESP_LOGI(TAG, "=======================================================================================");
|
||||||
|
ESP_LOGI(TAG, "On Device: window state %s", windowOpen ? "true" : "false");
|
||||||
|
simulateRoomTemperature(&temperature);
|
||||||
|
|
||||||
|
rc = aws_iot_shadow_init_json_document(JsonDocumentBuffer, sizeOfJsonDocumentBuffer);
|
||||||
|
if(SUCCESS == rc) {
|
||||||
|
rc = aws_iot_shadow_add_reported(JsonDocumentBuffer, sizeOfJsonDocumentBuffer, 2, &temperatureHandler,
|
||||||
|
&windowActuator);
|
||||||
|
if(SUCCESS == rc) {
|
||||||
|
rc = aws_iot_finalize_json_document(JsonDocumentBuffer, sizeOfJsonDocumentBuffer);
|
||||||
|
if(SUCCESS == rc) {
|
||||||
|
ESP_LOGI(TAG, "Update Shadow: %s", JsonDocumentBuffer);
|
||||||
|
rc = aws_iot_shadow_update(&mqttClient, CONFIG_AWS_EXAMPLE_THING_NAME, JsonDocumentBuffer,
|
||||||
|
ShadowUpdateStatusCallback, NULL, 4, true);
|
||||||
|
shadowUpdateInProgress = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ESP_LOGI(TAG, "*****************************************************************************************");
|
||||||
|
vTaskDelay(1000 / portTICK_RATE_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(SUCCESS != rc) {
|
||||||
|
ESP_LOGE(TAG, "An error occurred in the loop %d", rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Disconnecting");
|
||||||
|
rc = aws_iot_shadow_disconnect(&mqttClient);
|
||||||
|
|
||||||
|
if(SUCCESS != rc) {
|
||||||
|
ESP_LOGE(TAG, "Disconnect error %d", rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void initialise_wifi(void)
|
||||||
|
{
|
||||||
|
tcpip_adapter_init();
|
||||||
|
wifi_event_group = xEventGroupCreate();
|
||||||
|
ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );
|
||||||
|
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||||
|
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
|
||||||
|
ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
|
||||||
|
wifi_config_t wifi_config = {
|
||||||
|
.sta = {
|
||||||
|
.ssid = EXAMPLE_WIFI_SSID,
|
||||||
|
.password = EXAMPLE_WIFI_PASS,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
|
||||||
|
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
|
||||||
|
ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
|
||||||
|
ESP_ERROR_CHECK( esp_wifi_start() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void app_main()
|
||||||
|
{
|
||||||
|
initialise_wifi();
|
||||||
|
/* Temporarily pin task to core, due to FPU uncertainty */
|
||||||
|
xTaskCreatePinnedToCore(&aws_iot_task, "aws_iot_task", 16384+1024, NULL, 5, NULL, 1);
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
# Enable AWS IoT SDK support
|
||||||
|
CONFIG_AWS_IOT_SDK=y
|
||||||
|
|
||||||
|
# Enable FATFS read only with long filename support
|
||||||
|
# for loading Cert/CA/etc from filesystem
|
||||||
|
# (if enabled in config)
|
||||||
|
CONFIG_FATFS_CODEPAGE_437=y
|
||||||
|
CONFIG_FATFS_LFN_HEAP=y
|
|
@ -40,7 +40,7 @@
|
||||||
|
|
||||||
#include "mbedtls/platform.h"
|
#include "mbedtls/platform.h"
|
||||||
#include "mbedtls/net.h"
|
#include "mbedtls/net.h"
|
||||||
#include "mbedtls/debug.h"
|
#include "mbedtls/esp_debug.h"
|
||||||
#include "mbedtls/ssl.h"
|
#include "mbedtls/ssl.h"
|
||||||
#include "mbedtls/entropy.h"
|
#include "mbedtls/entropy.h"
|
||||||
#include "mbedtls/ctr_drbg.h"
|
#include "mbedtls/ctr_drbg.h"
|
||||||
|
@ -89,50 +89,6 @@ static const char *REQUEST = "GET " WEB_URL " HTTP/1.1\n"
|
||||||
extern const uint8_t server_root_cert_pem_start[] asm("_binary_server_root_cert_pem_start");
|
extern const uint8_t server_root_cert_pem_start[] asm("_binary_server_root_cert_pem_start");
|
||||||
extern const uint8_t server_root_cert_pem_end[] asm("_binary_server_root_cert_pem_end");
|
extern const uint8_t server_root_cert_pem_end[] asm("_binary_server_root_cert_pem_end");
|
||||||
|
|
||||||
#ifdef MBEDTLS_DEBUG_C
|
|
||||||
|
|
||||||
#define MBEDTLS_DEBUG_LEVEL 4
|
|
||||||
|
|
||||||
/* mbedtls debug function that translates mbedTLS debug output
|
|
||||||
to ESP_LOGx debug output.
|
|
||||||
|
|
||||||
MBEDTLS_DEBUG_LEVEL 4 means all mbedTLS debug output gets sent here,
|
|
||||||
and then filtered to the ESP logging mechanism.
|
|
||||||
*/
|
|
||||||
static void mbedtls_debug(void *ctx, int level,
|
|
||||||
const char *file, int line,
|
|
||||||
const char *str)
|
|
||||||
{
|
|
||||||
const char *MBTAG = "mbedtls";
|
|
||||||
char *file_sep;
|
|
||||||
|
|
||||||
/* Shorten 'file' from the whole file path to just the filename
|
|
||||||
|
|
||||||
This is a bit wasteful because the macros are compiled in with
|
|
||||||
the full _FILE_ path in each case.
|
|
||||||
*/
|
|
||||||
file_sep = rindex(file, '/');
|
|
||||||
if(file_sep)
|
|
||||||
file = file_sep+1;
|
|
||||||
|
|
||||||
switch(level) {
|
|
||||||
case 1:
|
|
||||||
ESP_LOGI(MBTAG, "%s:%d %s", file, line, str);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
ESP_LOGD(MBTAG, "%s:%d %s", file, line, str);
|
|
||||||
case 4:
|
|
||||||
ESP_LOGV(MBTAG, "%s:%d %s", file, line, str);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ESP_LOGE(MBTAG, "Unexpected log level %d: %s", level, str);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static esp_err_t event_handler(void *ctx, system_event_t *event)
|
static esp_err_t event_handler(void *ctx, system_event_t *event)
|
||||||
{
|
{
|
||||||
switch(event->event_id) {
|
switch(event->event_id) {
|
||||||
|
@ -240,9 +196,8 @@ static void https_get_task(void *pvParameters)
|
||||||
mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
|
mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
|
||||||
mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
|
mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
|
||||||
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
|
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
|
||||||
#ifdef MBEDTLS_DEBUG_C
|
#ifdef CONFIG_MBEDTLS_DEBUG
|
||||||
mbedtls_debug_set_threshold(MBEDTLS_DEBUG_LEVEL);
|
mbedtls_esp_enable_debug_log(&conf, 4);
|
||||||
mbedtls_ssl_conf_dbg(&conf, mbedtls_debug, NULL);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0)
|
if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0)
|
||||||
|
|
|
@ -72,7 +72,7 @@ endif
|
||||||
|
|
||||||
# Object files with embedded binaries to add to the component library
|
# Object files with embedded binaries to add to the component library
|
||||||
# Correspond to the files named in COMPONENT_EMBED_FILES & COMPONENT_EMBED_TXTFILES
|
# Correspond to the files named in COMPONENT_EMBED_FILES & COMPONENT_EMBED_TXTFILES
|
||||||
COMPONENT_EMBED_OBJS ?= $(addsuffix .bin.o,$(COMPONENT_EMBED_FILES)) $(addsuffix .txt.o,$(COMPONENT_EMBED_TXTFILES))
|
COMPONENT_EMBED_OBJS ?= $(addsuffix .bin.o,$(notdir $(COMPONENT_EMBED_FILES))) $(addsuffix .txt.o,$(notdir $(COMPONENT_EMBED_TXTFILES)))
|
||||||
|
|
||||||
# If we're called to compile something, we'll get passed the COMPONENT_INCLUDES
|
# If we're called to compile something, we'll get passed the COMPONENT_INCLUDES
|
||||||
# variable with all the include dirs from all the components in random order. This
|
# variable with all the include dirs from all the components in random order. This
|
||||||
|
@ -199,9 +199,9 @@ embed_txt/$$(notdir $(1)): $(call resolvepath,$(1),$(COMPONENT_PATH)) | embed_tx
|
||||||
|
|
||||||
# messing about with the embed_X subdirectory then using 'cd' for objcopy is because the
|
# messing about with the embed_X subdirectory then using 'cd' for objcopy is because the
|
||||||
# full path passed to OBJCOPY makes it into the name of the symbols in the .o file
|
# full path passed to OBJCOPY makes it into the name of the symbols in the .o file
|
||||||
$(1).$(2).o: embed_$(2)/$$(notdir $(1)) | $$(dir $(1))
|
$$(notdir $(1)).$(2).o: embed_$(2)/$$(notdir $(1))
|
||||||
$(summary) EMBED $$@
|
$(summary) EMBED $$@
|
||||||
cd embed_$(2); $(OBJCOPY) $(OBJCOPY_EMBED_ARGS) $$(notdir $$<) $$(call resolvepath,$$@,../)
|
cd embed_$(2); $(OBJCOPY) $(OBJCOPY_EMBED_ARGS) $$(notdir $$<) ../$$@
|
||||||
|
|
||||||
CLEAN_FILES += embed_$(2)/$$(notdir $(1))
|
CLEAN_FILES += embed_$(2)/$$(notdir $(1))
|
||||||
endef
|
endef
|
||||||
|
|
|
@ -30,7 +30,8 @@ help:
|
||||||
@echo "make clean - Remove all build output"
|
@echo "make clean - Remove all build output"
|
||||||
@echo "make size - Display the memory footprint of the app"
|
@echo "make size - Display the memory footprint of the app"
|
||||||
@echo "make erase_flash - Erase entire flash contents"
|
@echo "make erase_flash - Erase entire flash contents"
|
||||||
@echo "make monitor - Display serial output on terminal console"
|
@echo "make monitor - Run idf_monitor tool to monitor serial output from app"
|
||||||
|
@echo "make simple_monitor - Monitor serial output on terminal console"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "make app - Build just the app"
|
@echo "make app - Build just the app"
|
||||||
@echo "make app-flash - Flash just the app"
|
@echo "make app-flash - Flash just the app"
|
||||||
|
@ -127,17 +128,16 @@ COMPONENT_PATHS += $(abspath $(SRCDIRS))
|
||||||
# A component is buildable if it has a component.mk makefile in it
|
# A component is buildable if it has a component.mk makefile in it
|
||||||
COMPONENT_PATHS_BUILDABLE := $(foreach cp,$(COMPONENT_PATHS),$(if $(wildcard $(cp)/component.mk),$(cp)))
|
COMPONENT_PATHS_BUILDABLE := $(foreach cp,$(COMPONENT_PATHS),$(if $(wildcard $(cp)/component.mk),$(cp)))
|
||||||
|
|
||||||
# If TESTS_ALL set to 1, set TEST_COMPONENTS to all components
|
# If TESTS_ALL set to 1, set TEST_COMPONENTS_LIST to all components
|
||||||
ifeq ($(TESTS_ALL),1)
|
ifeq ($(TESTS_ALL),1)
|
||||||
TEST_COMPONENTS := $(COMPONENTS)
|
TEST_COMPONENTS_LIST := $(COMPONENTS)
|
||||||
|
else
|
||||||
|
# otherwise, use TEST_COMPONENTS
|
||||||
|
TEST_COMPONENTS_LIST := $(TEST_COMPONENTS)
|
||||||
endif
|
endif
|
||||||
|
TEST_COMPONENT_PATHS := $(foreach comp,$(TEST_COMPONENTS_LIST),$(firstword $(foreach dir,$(COMPONENT_DIRS),$(wildcard $(dir)/$(comp)/test))))
|
||||||
|
TEST_COMPONENT_NAMES := $(foreach comp,$(TEST_COMPONENT_PATHS),$(lastword $(subst /, ,$(dir $(comp))))_test)
|
||||||
|
|
||||||
# If TEST_COMPONENTS is set, create variables for building unit tests
|
|
||||||
ifdef TEST_COMPONENTS
|
|
||||||
override TEST_COMPONENTS := $(foreach comp,$(TEST_COMPONENTS),$(firstword $(foreach dir,$(COMPONENT_DIRS),$(wildcard $(dir)/$(comp)/test))))
|
|
||||||
TEST_COMPONENT_PATHS := $(TEST_COMPONENTS)
|
|
||||||
TEST_COMPONENT_NAMES := $(foreach comp,$(TEST_COMPONENTS),$(lastword $(subst /, ,$(dir $(comp))))_test)
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Initialise project-wide variables which can be added to by
|
# Initialise project-wide variables which can be added to by
|
||||||
# each component.
|
# each component.
|
||||||
|
|
507
tools/idf_monitor.py
Normal file
507
tools/idf_monitor.py
Normal file
|
@ -0,0 +1,507 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# esp-idf serial output monitor tool. Does some helpful things:
|
||||||
|
# - Looks up hex addresses in ELF file with addr2line
|
||||||
|
# - Reset ESP32 via serial RTS line (Ctrl-T Ctrl-R)
|
||||||
|
# - Run "make flash" (Ctrl-T Ctrl-F)
|
||||||
|
# - Run "make app-flash" (Ctrl-T Ctrl-A)
|
||||||
|
# - If gdbstub output is detected, gdb is automatically loaded
|
||||||
|
#
|
||||||
|
# Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
# Contains elements taken from miniterm "Very simple serial terminal" which
|
||||||
|
# is part of pySerial. https://github.com/pyserial/pyserial
|
||||||
|
# (C)2002-2015 Chris Liechti <cliechti@gmx.net>
|
||||||
|
#
|
||||||
|
# Originally released under BSD-3-Clause license.
|
||||||
|
#
|
||||||
|
from __future__ import print_function, division
|
||||||
|
import subprocess
|
||||||
|
import argparse
|
||||||
|
import codecs
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
try:
|
||||||
|
import queue
|
||||||
|
except ImportError:
|
||||||
|
import Queue as queue
|
||||||
|
import time
|
||||||
|
import sys
|
||||||
|
import serial
|
||||||
|
import serial.tools.miniterm as miniterm
|
||||||
|
import threading
|
||||||
|
import ctypes
|
||||||
|
|
||||||
|
key_description = miniterm.key_description
|
||||||
|
|
||||||
|
# Control-key characters
|
||||||
|
CTRL_A = '\x01'
|
||||||
|
CTRL_B = '\x02'
|
||||||
|
CTRL_F = '\x06'
|
||||||
|
CTRL_H = '\x08'
|
||||||
|
CTRL_R = '\x12'
|
||||||
|
CTRL_T = '\x14'
|
||||||
|
CTRL_RBRACKET = '\x1d' # Ctrl+]
|
||||||
|
|
||||||
|
# ANSI terminal codes
|
||||||
|
ANSI_BLUE = '\033[0;34m'
|
||||||
|
ANSI_RED = '\033[1;31m'
|
||||||
|
ANSI_YELLOW = '\033[0;33m'
|
||||||
|
ANSI_NORMAL = '\033[0m'
|
||||||
|
|
||||||
|
__version__ = "1.0"
|
||||||
|
|
||||||
|
# Tags for tuples in queues
|
||||||
|
TAG_KEY = 0
|
||||||
|
TAG_SERIAL = 1
|
||||||
|
|
||||||
|
# regex matches an potential PC value (0x4xxxxxxx)
|
||||||
|
MATCH_PCADDR = re.compile(r'0x4[0-9a-f]{7}', re.IGNORECASE)
|
||||||
|
|
||||||
|
class StoppableThread(object):
|
||||||
|
"""
|
||||||
|
Provide a Thread-like class which can be 'cancelled' via a subclass-provided
|
||||||
|
cancellation method.
|
||||||
|
|
||||||
|
Can be started and stopped multiple times.
|
||||||
|
|
||||||
|
Isn't an instance of type Thread because Python Thread objects can only be run once
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
self._thread = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def alive(self):
|
||||||
|
"""
|
||||||
|
Is 'alive' whenever the internal thread object exists
|
||||||
|
"""
|
||||||
|
return self._thread is not None
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
if self._thread is None:
|
||||||
|
self._thread = threading.Thread(target=self._run_outer)
|
||||||
|
self._thread.start()
|
||||||
|
|
||||||
|
def _cancel(self):
|
||||||
|
pass # override to provide cancellation functionality
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
pass # override for the main thread behaviour
|
||||||
|
|
||||||
|
def _run_outer(self):
|
||||||
|
try:
|
||||||
|
self.run()
|
||||||
|
finally:
|
||||||
|
self._thread = None
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
if self._thread is not None:
|
||||||
|
old_thread = self._thread
|
||||||
|
self._thread = None
|
||||||
|
self._cancel()
|
||||||
|
old_thread.join()
|
||||||
|
|
||||||
|
class ConsoleReader(StoppableThread):
|
||||||
|
""" Read input keys from the console and push them to the queue,
|
||||||
|
until stopped.
|
||||||
|
"""
|
||||||
|
def __init__(self, console, event_queue):
|
||||||
|
super(ConsoleReader, self).__init__()
|
||||||
|
self.console = console
|
||||||
|
self.event_queue = event_queue
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.console.setup()
|
||||||
|
try:
|
||||||
|
while self.alive:
|
||||||
|
try:
|
||||||
|
if os.name == 'nt':
|
||||||
|
# Windows kludge: because the console.cancel() method doesn't
|
||||||
|
# seem to work to unblock getkey() on the Windows implementation.
|
||||||
|
#
|
||||||
|
# So we only call getkey() if we know there's a key waiting for us.
|
||||||
|
import msvcrt
|
||||||
|
while not msvcrt.kbhit() and self.alive:
|
||||||
|
time.sleep(0.1)
|
||||||
|
if not self.alive:
|
||||||
|
break
|
||||||
|
c = self.console.getkey()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
c = '\x03'
|
||||||
|
if c is not None:
|
||||||
|
self.event_queue.put((TAG_KEY, c), False)
|
||||||
|
finally:
|
||||||
|
self.console.cleanup()
|
||||||
|
|
||||||
|
def _cancel(self):
|
||||||
|
self.console.cancel()
|
||||||
|
|
||||||
|
class SerialReader(StoppableThread):
|
||||||
|
""" Read serial data from the serial port and push to the
|
||||||
|
event queue, until stopped.
|
||||||
|
"""
|
||||||
|
def __init__(self, serial, event_queue):
|
||||||
|
super(SerialReader, self).__init__()
|
||||||
|
self.baud = serial.baudrate
|
||||||
|
self.serial = serial
|
||||||
|
self.event_queue = event_queue
|
||||||
|
if not hasattr(self.serial, 'cancel_read'):
|
||||||
|
# enable timeout for checking alive flag,
|
||||||
|
# if cancel_read not available
|
||||||
|
self.serial.timeout = 0.25
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
if not self.serial.is_open:
|
||||||
|
self.serial.baudrate = self.baud
|
||||||
|
self.serial.rts = True # Force an RTS reset on open
|
||||||
|
self.serial.open()
|
||||||
|
self.serial.rts = False
|
||||||
|
try:
|
||||||
|
while self.alive:
|
||||||
|
data = self.serial.read(self.serial.in_waiting or 1)
|
||||||
|
if len(data):
|
||||||
|
self.event_queue.put((TAG_SERIAL, data), False)
|
||||||
|
finally:
|
||||||
|
self.serial.close()
|
||||||
|
|
||||||
|
def _cancel(self):
|
||||||
|
if hasattr(self.serial, 'cancel_read'):
|
||||||
|
try:
|
||||||
|
self.serial.cancel_read()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Monitor(object):
|
||||||
|
"""
|
||||||
|
Monitor application main class.
|
||||||
|
|
||||||
|
This was originally derived from miniterm.Miniterm, but it turned out to be easier to write from scratch for this
|
||||||
|
purpose.
|
||||||
|
|
||||||
|
Main difference is that all event processing happens in the main thread, not the worker threads.
|
||||||
|
"""
|
||||||
|
def __init__(self, serial_instance, elf_file, make="make"):
|
||||||
|
super(Monitor, self).__init__()
|
||||||
|
self.event_queue = queue.Queue()
|
||||||
|
self.console = miniterm.Console()
|
||||||
|
if os.name == 'nt':
|
||||||
|
sys.stderr = ANSIColorConverter(sys.stderr)
|
||||||
|
self.console.output = ANSIColorConverter(self.console.output)
|
||||||
|
self.console.byte_output = ANSIColorConverter(self.console.byte_output)
|
||||||
|
|
||||||
|
self.serial = serial_instance
|
||||||
|
self.console_reader = ConsoleReader(self.console, self.event_queue)
|
||||||
|
self.serial_reader = SerialReader(self.serial, self.event_queue)
|
||||||
|
self.elf_file = elf_file
|
||||||
|
self.make = make
|
||||||
|
self.menu_key = CTRL_T
|
||||||
|
self.exit_key = CTRL_RBRACKET
|
||||||
|
|
||||||
|
# internal state
|
||||||
|
self._pressed_menu_key = False
|
||||||
|
self._read_line = b""
|
||||||
|
self._gdb_buffer = b""
|
||||||
|
|
||||||
|
def main_loop(self):
|
||||||
|
self.console_reader.start()
|
||||||
|
self.serial_reader.start()
|
||||||
|
try:
|
||||||
|
while self.console_reader.alive and self.serial_reader.alive:
|
||||||
|
(event_tag, data) = self.event_queue.get()
|
||||||
|
if event_tag == TAG_KEY:
|
||||||
|
self.handle_key(data)
|
||||||
|
elif event_tag == TAG_SERIAL:
|
||||||
|
self.handle_serial_input(data)
|
||||||
|
else:
|
||||||
|
raise RuntimeError("Bad event data %r" % ((event_tag,data),))
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
self.console_reader.stop()
|
||||||
|
self.serial_reader.stop()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
sys.stderr.write(ANSI_NORMAL + "\n")
|
||||||
|
|
||||||
|
def handle_key(self, key):
|
||||||
|
if self._pressed_menu_key:
|
||||||
|
self.handle_menu_key(key)
|
||||||
|
self._pressed_menu_key = False
|
||||||
|
elif key == self.menu_key:
|
||||||
|
self._pressed_menu_key = True
|
||||||
|
elif key == self.exit_key:
|
||||||
|
self.console_reader.stop()
|
||||||
|
self.serial_reader.stop()
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
self.serial.write(codecs.encode(key))
|
||||||
|
except serial.SerialException:
|
||||||
|
pass # this shouldn't happen, but sometimes port has closed in serial thread
|
||||||
|
|
||||||
|
def handle_serial_input(self, data):
|
||||||
|
# this may need to be made more efficient, as it pushes out a byte
|
||||||
|
# at a time to the console
|
||||||
|
for b in data:
|
||||||
|
self.console.write_bytes(b)
|
||||||
|
if b == b'\n': # end of line
|
||||||
|
self.handle_serial_input_line(self._read_line.strip())
|
||||||
|
self._read_line = b""
|
||||||
|
else:
|
||||||
|
self._read_line += b
|
||||||
|
self.check_gdbstub_trigger(b)
|
||||||
|
|
||||||
|
def handle_serial_input_line(self, line):
|
||||||
|
for m in re.finditer(MATCH_PCADDR, line):
|
||||||
|
self.lookup_pc_address(m.group())
|
||||||
|
|
||||||
|
def handle_menu_key(self, c):
|
||||||
|
if c == self.exit_key or c == self.menu_key: # send verbatim
|
||||||
|
self.serial.write(codecs.encode(c))
|
||||||
|
elif c in [ CTRL_H, 'h', 'H', '?' ]:
|
||||||
|
sys.stderr.write(self.get_help_text())
|
||||||
|
elif c == CTRL_R: # Reset device via RTS
|
||||||
|
self.serial.setRTS(True)
|
||||||
|
time.sleep(0.2)
|
||||||
|
self.serial.setRTS(False)
|
||||||
|
elif c == CTRL_F: # Recompile & upload
|
||||||
|
self.run_make("flash")
|
||||||
|
elif c == CTRL_A: # Recompile & upload app only
|
||||||
|
self.run_make("app-flash")
|
||||||
|
else:
|
||||||
|
sys.stderr.write('--- unknown menu character {} --\n'.format(key_description(c)))
|
||||||
|
|
||||||
|
def get_help_text(self):
|
||||||
|
return """
|
||||||
|
--- idf_monitor ({version}) - ESP-IDF monitor tool
|
||||||
|
--- based on miniterm from pySerial
|
||||||
|
---
|
||||||
|
--- {exit:8} Exit program
|
||||||
|
--- {menu:8} Menu escape key, followed by:
|
||||||
|
--- Menu keys:
|
||||||
|
--- {menu:7} Send the menu character itself to remote
|
||||||
|
--- {exit:7} Send the exit character itself to remote
|
||||||
|
--- {reset:7} Reset target board via RTS line
|
||||||
|
--- {make:7} Run 'make flash' to build & flash
|
||||||
|
--- {appmake:7} Run 'make app-flash to build & flash app
|
||||||
|
""".format(version=__version__,
|
||||||
|
exit=key_description(self.exit_key),
|
||||||
|
menu=key_description(self.menu_key),
|
||||||
|
reset=key_description(CTRL_R),
|
||||||
|
make=key_description(CTRL_F),
|
||||||
|
appmake=key_description(CTRL_A),
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
""" Use 'with self' to temporarily disable monitoring behaviour """
|
||||||
|
self.serial_reader.stop()
|
||||||
|
self.console_reader.stop()
|
||||||
|
|
||||||
|
def __exit__(self, *args, **kwargs):
|
||||||
|
""" Use 'with self' to temporarily disable monitoring behaviour """
|
||||||
|
self.console_reader.start()
|
||||||
|
self.serial_reader.start()
|
||||||
|
|
||||||
|
def prompt_next_action(self, reason):
|
||||||
|
self.console.setup() # set up console to trap input characters
|
||||||
|
try:
|
||||||
|
sys.stderr.write(ANSI_RED)
|
||||||
|
sys.stderr.write("--- {}\n".format(reason))
|
||||||
|
sys.stderr.write("--- Press {} to exit monitor.\n"
|
||||||
|
.format(key_description(self.exit_key)))
|
||||||
|
sys.stderr.write("--- Press {} to run 'make flash'.\n"
|
||||||
|
.format(key_description(CTRL_F)))
|
||||||
|
sys.stderr.write("--- Press {} to run 'make app-flash'.\n"
|
||||||
|
.format(key_description(CTRL_A)))
|
||||||
|
sys.stderr.write("--- Press any other key to resume monitor (resets target).\n")
|
||||||
|
sys.stderr.write(ANSI_NORMAL)
|
||||||
|
k = self.console.getkey()
|
||||||
|
finally:
|
||||||
|
self.console.cleanup()
|
||||||
|
if k == self.exit_key:
|
||||||
|
self.event_queue.put((TAG_KEY, k))
|
||||||
|
elif k in [ CTRL_F, CTRL_A ]:
|
||||||
|
self.event_queue.put((TAG_KEY, self.menu_key))
|
||||||
|
self.event_queue.put((TAG_KEY, k))
|
||||||
|
|
||||||
|
def run_make(self, target):
|
||||||
|
with self:
|
||||||
|
sys.stderr.write("%s--- Running make %s...\n" % (ANSI_NORMAL, target))
|
||||||
|
p = subprocess.Popen([self.make,
|
||||||
|
target ])
|
||||||
|
try:
|
||||||
|
p.wait()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
p.wait()
|
||||||
|
if p.returncode != 0:
|
||||||
|
self.prompt_next_action("Build failed")
|
||||||
|
|
||||||
|
def lookup_pc_address(self, pc_addr):
|
||||||
|
translation = subprocess.check_output(
|
||||||
|
["xtensa-esp32-elf-addr2line", "-pfia",
|
||||||
|
"-e", self.elf_file, pc_addr],
|
||||||
|
cwd=".")
|
||||||
|
if not "?? ??:0" in translation:
|
||||||
|
sys.stderr.write(ANSI_YELLOW + translation + ANSI_NORMAL)
|
||||||
|
|
||||||
|
def check_gdbstub_trigger(self, c):
|
||||||
|
self._gdb_buffer = self._gdb_buffer[-6:] + c # keep the last 7 characters seen
|
||||||
|
m = re.match(b"\\$(T..)#(..)", self._gdb_buffer) # look for a gdb "reason" for a break
|
||||||
|
if m is not None:
|
||||||
|
try:
|
||||||
|
chsum = sum(ord(p) for p in m.group(1)) & 0xFF
|
||||||
|
calc_chsum = int(m.group(2), 16)
|
||||||
|
except ValueError:
|
||||||
|
return # payload wasn't valid hex digits
|
||||||
|
if chsum == calc_chsum:
|
||||||
|
self.run_gdb()
|
||||||
|
else:
|
||||||
|
sys.stderr.write("Malformed gdb message... calculated checksum %02x received %02x\n" % (chsum, calc_chsum))
|
||||||
|
|
||||||
|
|
||||||
|
def run_gdb(self):
|
||||||
|
with self: # disable console control
|
||||||
|
sys.stderr.write(ANSI_NORMAL)
|
||||||
|
try:
|
||||||
|
subprocess.call(["xtensa-esp32-elf-gdb",
|
||||||
|
"-ex", "set serial baud %d" % self.serial.baudrate,
|
||||||
|
"-ex", "target remote %s" % self.serial.port,
|
||||||
|
"-ex", "interrupt", # monitor has already parsed the first 'reason' command, need a second
|
||||||
|
self.elf_file], cwd=".")
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
pass # happens on Windows, maybe other OSes
|
||||||
|
self.prompt_next_action("gdb exited")
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser("idf_monitor - a serial output monitor for esp-idf")
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'--port', '-p',
|
||||||
|
help='Serial port device',
|
||||||
|
default=os.environ.get('ESPTOOL_PORT', '/dev/ttyUSB0')
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'--baud', '-b',
|
||||||
|
help='Serial port baud rate',
|
||||||
|
type=int,
|
||||||
|
default=os.environ.get('MONITOR_BAUD', 115200))
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'--make', '-m',
|
||||||
|
help='Command to run make',
|
||||||
|
type=str, default='make')
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'elf_file', help='ELF file of application',
|
||||||
|
type=argparse.FileType('r'))
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
serial_instance = serial.serial_for_url(args.port, args.baud,
|
||||||
|
do_not_open=True)
|
||||||
|
serial_instance.dtr = False
|
||||||
|
serial_instance.rts = False
|
||||||
|
|
||||||
|
args.elf_file.close() # don't need this as a file
|
||||||
|
|
||||||
|
# remove the parallel jobserver arguments from MAKEFLAGS, as any
|
||||||
|
# parent make is only running 1 job (monitor), so we can re-spawn
|
||||||
|
# all of the child makes we need (the -j argument remains part of
|
||||||
|
# MAKEFLAGS)
|
||||||
|
try:
|
||||||
|
makeflags = os.environ["MAKEFLAGS"]
|
||||||
|
makeflags = re.sub(r"--jobserver[^ =]*=[0-9,]+ ?", "", makeflags)
|
||||||
|
os.environ["MAKEFLAGS"] = makeflags
|
||||||
|
except KeyError:
|
||||||
|
pass # not running a make jobserver
|
||||||
|
|
||||||
|
monitor = Monitor(serial_instance, args.elf_file.name, args.make)
|
||||||
|
|
||||||
|
sys.stderr.write('--- idf_monitor on {p.name} {p.baudrate} ---\n'.format(
|
||||||
|
p=serial_instance))
|
||||||
|
sys.stderr.write('--- Quit: {} | Menu: {} | Help: {} followed by {} ---\n'.format(
|
||||||
|
key_description(monitor.exit_key),
|
||||||
|
key_description(monitor.menu_key),
|
||||||
|
key_description(monitor.menu_key),
|
||||||
|
key_description(CTRL_H)))
|
||||||
|
|
||||||
|
monitor.main_loop()
|
||||||
|
|
||||||
|
if os.name == 'nt':
|
||||||
|
# Windows console stuff
|
||||||
|
|
||||||
|
STD_OUTPUT_HANDLE = -11
|
||||||
|
STD_ERROR_HANDLE = -12
|
||||||
|
|
||||||
|
# wincon.h values
|
||||||
|
FOREGROUND_INTENSITY = 8
|
||||||
|
FOREGROUND_GREY = 7
|
||||||
|
|
||||||
|
# matches the ANSI color change sequences that IDF sends
|
||||||
|
RE_ANSI_COLOR = re.compile(b'\033\\[([01]);3([0-7])m')
|
||||||
|
|
||||||
|
# list mapping the 8 ANSI colors (the indexes) to Windows Console colors
|
||||||
|
ANSI_TO_WINDOWS_COLOR = [ 0, 4, 2, 6, 1, 5, 3, 7 ]
|
||||||
|
|
||||||
|
GetStdHandle = ctypes.windll.kernel32.GetStdHandle
|
||||||
|
SetConsoleTextAttribute = ctypes.windll.kernel32.SetConsoleTextAttribute
|
||||||
|
|
||||||
|
class ANSIColorConverter(object):
|
||||||
|
"""Class to wrap a file-like output stream, intercept ANSI color codes,
|
||||||
|
and convert them into calls to Windows SetConsoleTextAttribute.
|
||||||
|
|
||||||
|
Doesn't support all ANSI terminal code escape sequences, only the sequences IDF uses.
|
||||||
|
|
||||||
|
Ironically, in Windows this console output is normally wrapped by winpty which will then detect the console text
|
||||||
|
color changes and convert these back to ANSI color codes for MSYS' terminal to display. However this is the
|
||||||
|
least-bad working solution, as winpty doesn't support any "passthrough" mode for raw output.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, output):
|
||||||
|
self.output = output
|
||||||
|
self.handle = GetStdHandle(STD_ERROR_HANDLE if self.output == sys.stderr else STD_OUTPUT_HANDLE)
|
||||||
|
self.matched = b''
|
||||||
|
|
||||||
|
def write(self, data):
|
||||||
|
for b in data:
|
||||||
|
l = len(self.matched)
|
||||||
|
if b == '\033': # ESC
|
||||||
|
self.matched = b
|
||||||
|
elif (l == 1 and b == '[') or (1 < l < 7):
|
||||||
|
self.matched += b
|
||||||
|
if self.matched == ANSI_NORMAL: # reset console
|
||||||
|
SetConsoleTextAttribute(self.handle, FOREGROUND_GREY)
|
||||||
|
self.matched = b''
|
||||||
|
elif len(self.matched) == 7: # could be an ANSI sequence
|
||||||
|
m = re.match(RE_ANSI_COLOR, self.matched)
|
||||||
|
if m is not None:
|
||||||
|
color = ANSI_TO_WINDOWS_COLOR[int(m.group(2))]
|
||||||
|
if m.group(1) == b'1':
|
||||||
|
color |= FOREGROUND_INTENSITY
|
||||||
|
SetConsoleTextAttribute(self.handle, color)
|
||||||
|
else:
|
||||||
|
self.output.write(self.matched) # not an ANSI color code, display verbatim
|
||||||
|
self.matched = b''
|
||||||
|
else:
|
||||||
|
self.output.write(b)
|
||||||
|
self.matched = b''
|
||||||
|
|
||||||
|
def flush(self):
|
||||||
|
self.output.flush()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -42,13 +42,14 @@ void unity_testcase_register(struct test_desc_t* desc)
|
||||||
if (!s_unity_tests_first)
|
if (!s_unity_tests_first)
|
||||||
{
|
{
|
||||||
s_unity_tests_first = desc;
|
s_unity_tests_first = desc;
|
||||||
|
s_unity_tests_last = desc;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
s_unity_tests_last->next = desc;
|
struct test_desc_t* temp = s_unity_tests_first;
|
||||||
|
s_unity_tests_first = desc;
|
||||||
|
s_unity_tests_first->next = temp;
|
||||||
}
|
}
|
||||||
s_unity_tests_last = desc;
|
|
||||||
desc->next = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unity_run_single_test(const struct test_desc_t* test)
|
static void unity_run_single_test(const struct test_desc_t* test)
|
||||||
|
|
|
@ -57,7 +57,6 @@ CONFIG_ESPTOOLPY_FLASHSIZE="4MB"
|
||||||
CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
|
CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
|
||||||
CONFIG_ESPTOOLPY_BEFORE_RESET=y
|
CONFIG_ESPTOOLPY_BEFORE_RESET=y
|
||||||
# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set
|
# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set
|
||||||
# CONFIG_ESPTOOLPY_BEFORE_ESP32R0 is not set
|
|
||||||
CONFIG_ESPTOOLPY_BEFORE="default_reset"
|
CONFIG_ESPTOOLPY_BEFORE="default_reset"
|
||||||
CONFIG_ESPTOOLPY_AFTER_RESET=y
|
CONFIG_ESPTOOLPY_AFTER_RESET=y
|
||||||
# CONFIG_ESPTOOLPY_AFTER_NORESET is not set
|
# CONFIG_ESPTOOLPY_AFTER_NORESET is not set
|
||||||
|
@ -89,6 +88,12 @@ CONFIG_OPTIMIZATION_LEVEL_DEBUG=y
|
||||||
#
|
#
|
||||||
# Component config
|
# Component config
|
||||||
#
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Amazon Web Service IoT Config
|
||||||
|
#
|
||||||
|
CONFIG_AWS_IOT_MQTT_HOST=""
|
||||||
|
CONFIG_AWS_IOT_MQTT_PORT=8883
|
||||||
# CONFIG_BT_ENABLED is not set
|
# CONFIG_BT_ENABLED is not set
|
||||||
CONFIG_BT_RESERVE_DRAM=0
|
CONFIG_BT_RESERVE_DRAM=0
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue